{"openapi":"3.1.0","info":{"title":"MYEQ Production Intelligence API","version":"1.0.0","description":"Turn creative intent into an inspectable, durable and repairable audiovisual production.\n\nProduct maturity: foundation. This contract exposes foundations and experimental operations; it does not claim that the complete storyboard product is finished. Read /api/v1/product/manifest for the authoritative product lifecycle, authority classes and maturity definitions."},"servers":[{"url":"https://myeq-full-1015143369529.europe-west4.run.app"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"CommerceProduct":{"type":"object","required":["title"],"properties":{"title":{"type":"string","example":"Aurora Wireless Headphones"},"imageUrl":{"type":"string","format":"uri","description":"Absolute product image URL; used as the LTX start frame."},"price":{"type":"string","example":"$129"},"url":{"type":"string","format":"uri"},"description":{"type":"string"}}},"DeliveryRequest":{"type":"object","required":["video","destinations"],"properties":{"video":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","example":"https://cdn.myeq/out.mp4"},"title":{"type":"string"}}},"destinations":{"type":"array","maxItems":10,"items":{"oneOf":[{"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri"},"secret":{"type":"string","description":"When set, the payload is HMAC-signed (X-MYEQ-Signature)."}}},{"type":"object","required":["type","to"],"properties":{"type":{"type":"string","enum":["email"]},"to":{"type":"string","format":"email"}}},{"type":"object","required":["type","accountRef"],"properties":{"type":{"type":"string","enum":["google_drive"]},"accountRef":{"type":"string"},"folderId":{"type":"string"}}}]}},"meta":{"type":"object","additionalProperties":true}}},"CommerceVideoRequest":{"type":"object","required":["trigger","product"],"properties":{"trigger":{"type":"string","enum":["abandoned_cart","post_purchase","objection_handling","cross_sell"],"description":"abandoned_cart/objection-handling → objection-handling video; post_purchase/cross_sell → cross-sell video."},"product":{"$ref":"#/components/schemas/CommerceProduct"},"customer":{"type":"object","properties":{"firstName":{"type":"string","example":"Alex"},"locale":{"type":"string","example":"en-US","description":"Spoken language of the generated video."}}},"objections":{"type":"array","items":{"type":"string"},"description":"Hesitations to address (abandoned cart).","example":["too expensive","not sure about quality"]},"crossSellProducts":{"type":"array","items":{"$ref":"#/components/schemas/CommerceProduct"},"description":"Complementary products (post-purchase)."},"brandName":{"type":"string"},"ctaUrl":{"type":"string","format":"uri"},"aspectRatio":{"type":"string","enum":["16:9","9:16","1:1","4:5","2:3"],"default":"9:16"},"durationSeconds":{"type":"number","minimum":1,"maximum":60,"default":8},"shopDomain":{"type":"string","example":"my-store.myshopify.com"},"externalRef":{"type":"string","description":"Your cart/order id for correlation + idempotency."},"dryRun":{"type":"boolean","default":false,"description":"Preview the resolved brief + LTX payload without generating (no credits)."}}},"VideoStartRequest":{"type":"object","required":["title","prompt"],"properties":{"title":{"type":"string","example":"My AI Movie"},"prompt":{"type":"string","example":"A cinematic journey through a black hole"},"duration":{"type":"number","minimum":5,"maximum":3600,"default":60,"description":"Total video duration in seconds (up to 60 minutes). Scene count is derived automatically in 5-second clips."},"scene_count":{"type":"number","minimum":1,"maximum":720,"description":"Optional override for scene count (up to 720 scenes). When omitted, derived from duration using 5-second scenes."},"include_captions":{"type":"boolean","default":true},"referenceImageUrl":{"type":"string","format":"uri"},"videoModel":{"type":"string","default":"MiniMax-Hailuo-2.3"},"render_provider":{"type":"string","enum":["minimax","ltx","auto"],"default":"auto","description":"Force a provider or delegate routing to orchestrator policy."},"execution_target":{"type":"string","enum":["minimax","ltx_render","auto"],"default":"auto","description":"Optional advanced override for runtime execution target."},"workflow_template":{"type":"string","maxLength":120,"description":"Optional workflow/pipeline template (LTX oriented)."},"operator_mode":{"type":"string","enum":["automatic","supervised"],"default":"automatic","description":"Supervised mode enables operator checkpoints between scene generations."},"input_modality":{"type":"string","enum":["image_to_video","audio_to_video"],"default":"image_to_video"},"source_audio_url":{"type":"string","format":"uri"},"negative_prompt":{"type":"string","maxLength":2000},"resolution":{"type":"string","enum":["768P","1080P"],"default":"768P"},"aspect_ratio":{"type":"string","enum":["16:9","9:16","1:1"],"default":"16:9"},"orchestration_mode":{"type":"string","enum":["automatic","supervised"],"default":"automatic"},"include_music":{"type":"boolean","default":false},"include_voiceover":{"type":"boolean","default":false},"include_photos":{"type":"boolean","default":true}}},"ImageGenerateRequest":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","example":"An oil painting of a futuristic city"},"aspect_ratio":{"type":"string","enum":["1:1","16:9","4:3","3:2","2:3","3:4","9:16","21:9"],"default":"16:9"}}},"StoryboardPhotoBatchRequest":{"type":"object","required":["projectId","prompt","count"],"properties":{"projectId":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$","minLength":3,"maxLength":120},"prompt":{"type":"string","minLength":1,"maxLength":12000,"example":"Product hero on a matte concrete plinth, soft north light"},"count":{"type":"integer","minimum":1,"maximum":200,"description":"Frames to render. The accepted maximum is lower than 200 in practice and depends on continuityMode, because this endpoint renders inline. Above the ceiling the request is rejected with 413 before any charge; the response reports max_synchronous_count."},"continuityMode":{"type":"string","enum":["independent","master_reference","chain"],"default":"chain","description":"chain conditions each frame on the previous frame's output and therefore renders sequentially, which is what keeps identity stable across a sequence but also caps how many frames one request can finish. independent renders in parallel with no shared reference. master_reference renders in parallel against a fixed reference and requires referenceImageUrls."},"aspectRatio":{"type":"string","enum":["16:9","9:16","1:1"],"default":"16:9"},"engine":{"type":"string","enum":["auto","myeq_images","nano_banana"],"default":"auto"},"referenceImageUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":16,"description":"Required when continuityMode=master_reference."},"frames":{"type":"array","maxItems":200,"description":"Per-frame overrides. When present it must contain exactly count entries.","items":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","minLength":1,"maxLength":12000},"sceneId":{"type":"string","maxLength":200},"role":{"type":"string","enum":["start","end"]},"title":{"type":"string","maxLength":500},"referenceImageUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":16}}}},"styleNotes":{"type":"string","maxLength":4000},"negativePrompt":{"type":"string","maxLength":4000},"seed":{"type":"integer","minimum":0,"maximum":2147483647}}},"StoryboardImageGenerateRequest":{"type":"object","required":["expectedExecutionManifestArtifactHash"],"description":"The manifest hash pins execution to the exact plan that was priced. Every expected* field is an optimistic-concurrency check: supply what plan returned and the request is refused with 409 if anything moved underneath it.","properties":{"expectedExecutionManifestArtifactHash":{"type":"string","maxLength":180,"description":"Required. Copy executionManifestArtifact.artifactHash from the plan response."},"expectedExecutionManifestId":{"type":"string","maxLength":180,"description":"Optional. executionManifest.id from the plan response."},"expectedPlanArtifactHash":{"type":"string","maxLength":180,"description":"Optional. planArtifact.artifactHash from the plan response."},"expectedScriptRevisionId":{"type":"string","maxLength":180,"description":"Optional. Refuses if the script moved since planning."},"expectedStoryboardRevisionId":{"type":"string","maxLength":180,"description":"Optional. Refuses if the storyboard moved since planning."},"requirementIds":{"type":"array","items":{"type":"string","maxLength":180},"description":"Optional. Generate only these requirements instead of every pending one."}}},"StoryboardImageGenerateAccepted":{"type":"object","description":"The polling handle is job.id. There is no top-level jobId field.","properties":{"ok":{"type":"boolean"},"accepted":{"type":"boolean"},"resume":{"type":"boolean","description":"True when only part of the manifest was dispatched, so a further call is needed."},"storyboardImageWorkPlanId":{"type":"string"},"preparedStoryboardRevisionId":{"type":"string"},"executionManifest":{"type":"object","additionalProperties":true},"plan":{"type":"object","additionalProperties":true},"job":{"type":"object","description":"Pass job.id as {jobId} to film-intelligence/jobs/{jobId}.","properties":{"id":{"type":"string","description":"The job id to poll."},"operation":{"type":"string"},"status":{"type":"string"},"requestedImageCount":{"type":"integer"},"requirementIds":{"type":"array","items":{"type":"string"}},"requiredCredits":{"type":"integer"},"alreadyCharged":{"type":"boolean"}}}}},"StoryboardImageGenerateAlreadySatisfied":{"type":"object","description":"Returned with HTTP 200, not 202, when every requirement selected for generation was already satisfied by a prior call. This is the idempotent no-op case: nothing is charged, no job is created, and there is no job.id to poll. A resumed or replayed request must check accepted before treating the response as \"a job is running\".","properties":{"ok":{"type":"boolean"},"accepted":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["all_requirements_satisfied"]},"plan":{"type":"object","additionalProperties":true},"executionManifest":{"type":"object","additionalProperties":true}}},"PhotoSequenceReviewRequest":{"type":"object","required":["decisions"],"properties":{"decisions":{"type":"array","minItems":1,"maxItems":32,"items":{"type":"object","required":["frameIndex","decision","note"],"properties":{"frameIndex":{"type":"integer","minimum":0,"maximum":31},"decision":{"type":"string","enum":["accept","repair"]},"note":{"type":"string","minLength":1,"maxLength":4000,"description":"Why. Recorded as the human rationale for the decision."},"repairPromptAdditions":{"type":"array","items":{"type":"string","minLength":1,"maxLength":1000},"maxItems":50},"approveForTraining":{"type":"boolean","default":false}}}}}},"BatchOverCapacityResponse":{"type":"object","required":["code","requested_count","max_synchronous_count","no_credits_spent"],"description":"Returned when a synchronous batch cannot finish inside one request. Nothing was charged.","properties":{"error":{"type":"string","const":"batch_exceeds_synchronous_capacity"},"code":{"type":"string","const":"batch_exceeds_synchronous_capacity"},"message":{"type":"string"},"requested_count":{"type":"integer"},"max_synchronous_count":{"type":"integer","description":"Largest count this endpoint accepts for the requested continuityMode."},"continuity_mode":{"type":"string","enum":["independent","master_reference","chain"]},"no_credits_spent":{"type":"boolean","const":true},"durable_alternative":{"type":"object","description":"The supervised endpoints to use for the full batch.","properties":{"plan":{"type":"string"},"generate":{"type":"string"},"poll":{"type":"string"}}}}},"MusicGenerateRequest":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","example":"Upbeat techno with heavy bass"},"duration":{"type":"number","default":30},"instrumental":{"type":"boolean","default":false}}},"TtsRequest":{"type":"object","required":["text"],"properties":{"text":{"type":"string","example":"Welcome to the future of neural video."},"voice_id":{"type":"string","default":"speech-2.8-hd"}}},"ApiErrorResponse":{"type":"object","required":["ok","code","message"],"properties":{"ok":{"type":"boolean","const":false},"code":{"type":"string"},"message":{"type":"string"},"details":{},"requestId":{"type":"string"},"noCreditsSpent":{"type":"boolean"},"retryable":{"type":"boolean"}}},"WorkspaceRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80,"example":"Brand studio"}}},"WorkspaceListResponse":{"type":"object","properties":{"workspaces":{"type":"array","items":{"type":"object"}}}},"VideoCreateJobRequest":{"$ref":"#/components/schemas/VideoStartRequest"},"UploadUrlRequest":{"type":"object","required":["filename","contentType"],"properties":{"filename":{"type":"string","example":"image.jpg"},"contentType":{"type":"string","example":"image/jpeg"},"category":{"type":"string","enum":["MUSIC","VIDEOS","PHOTOS","SFX","VOICES"],"default":"PHOTOS"},"sizeBytes":{"type":"integer","minimum":1,"description":"Optional during compatibility rollout. Active editor clients send it and the server rejects values over the category max."}}},"CreativeAgentSettingsRequest":{"type":"object","properties":{"authorSignature":{"type":"string","example":"Noir poético con tensión ética","maxLength":160},"creativeGoals":{"type":"array","items":{"type":"string"},"maxItems":12},"bannedTopics":{"type":"array","items":{"type":"string"},"maxItems":20},"preferredNarrativeTone":{"type":"string","enum":["cinematic","documentary","educational","experimental","commercial"]},"preferredVisualStyle":{"type":"string","maxLength":1000},"preferredMusicDirection":{"type":"string","maxLength":1000},"pacingPreference":{"type":"integer","minimum":1,"maximum":5},"ethicalGuardrails":{"type":"array","items":{"type":"string"},"maxItems":20},"subtitlePolicy":{"type":"object","properties":{"primaryLanguage":{"type":"string","enum":["en","es","de","pt","fr","ja","zh","ru"]},"additionalLanguages":{"type":"array","items":{"type":"string","enum":["en","es","de","pt","fr","ja","zh","ru"]},"maxItems":4},"style":{"type":"string","enum":["verbatim","clean","cinematic"]}}},"governanceMode":{"type":"string","enum":["strict","balanced","creative"]},"modelRouting":{"type":"object","properties":{"generalBrain":{"type":"string","enum":["gemini"],"default":"gemini"},"assetGenerator":{"type":"string","enum":["minimax"],"default":"minimax"},"riskTolerance":{"type":"string","enum":["low","medium","high"]}}}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/v1/video/create-job":{"post":{"tags":["Video"],"summary":"Create a spend-gated video generation job","description":"Backward-compatible alias for /api/v1/video/create. This endpoint may start paid generation only after successful authentication, request validation, deterministic preflight, provider capability validation, and credit/BYOK authorization. LTX lip-sync preflight failures return 422 with no_credits_spent=true and no provider dispatch.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Recommended for paid generation retries; reused keys are deduplicated per user and body hash."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreateJobRequest"}}}},"responses":{"202":{"description":"Job accepted after credit/BYOK authorization and dispatch recorded"},"402":{"description":"Insufficient credits; provider was not dispatched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Preflight or validation failed; no credits spent for pre-dispatch failures","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"425":{"description":"Idempotent request still processing"}}}},"/api/v1/workspaces":{"get":{"tags":["Workspaces"],"summary":"List accessible workspaces","responses":{"200":{"description":"Workspace list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceListResponse"}}}},"401":{"description":"Unauthorized"}}},"post":{"tags":["Workspaces"],"summary":"Create a team workspace","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceRequest"}}}},"responses":{"201":{"description":"Workspace created"},"400":{"description":"Invalid name"},"401":{"description":"Unauthorized"}}},"delete":{"tags":["Workspaces"],"summary":"Delete/detach a non-protected workspace","description":"Requires owner membership. Personal/default and last remaining workspaces are protected. Assets are not permanently deleted by this endpoint.","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Workspace removed and nextWorkspaceId returned"},"403":{"description":"Forbidden or protected workspace"},"409":{"description":"Cannot delete last workspace"}}}},"/api/v1/storage/preview":{"get":{"tags":["Storage"],"summary":"Proxy an allowlisted image preview URL","description":"No open proxy: only HTTPS URLs from approved hosts are fetched; Wasabi objects are signed with a one-hour TTL.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"}}],"responses":{"200":{"description":"Image stream"},"400":{"description":"Missing or disallowed URL"},"413":{"description":"Image too large"},"415":{"description":"Remote resource is not an image"}}}},"/api/v1/video/start":{"post":{"tags":["Video"],"summary":"Create and start a long-video job","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoStartRequest"}}}},"responses":{"202":{"description":"Job started"}}}},"/api/v1/commerce/videos":{"post":{"tags":["Commerce"],"summary":"Generate a personalized commerce video (abandoned cart / post-purchase)","description":"Generate a short vertical LTX video for a shopper from a commercial event. trigger=abandoned_cart produces an objection-handling video; trigger=post_purchase produces a cross-sell video. Send dryRun=true to preview the resolved brief + payload without spending credits. LTX only.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceVideoRequest"}}}},"responses":{"200":{"description":"Dry-run preview (brief + payload, nothing generated)"},"202":{"description":"Generation started (job returned)"},"422":{"description":"Invalid request"},"503":{"description":"Commerce video API not enabled"}}}},"/api/v1/delivery":{"post":{"tags":["Delivery"],"summary":"Deliver a finished video to agnostic destinations (webhook / email / Drive)","description":"Delivers an already-rendered video; spends NO generation credits. Webhook is fully wired (SSRF-guarded + HMAC-signed via X-MYEQ-Signature); email and google_drive return an honest \"unsupported\" until their adapters land. Feature-flagged (UNIVERSAL_DELIVERY_ENABLED).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryRequest"}}}},"responses":{"200":{"description":"Per-destination delivery results"},"422":{"description":"Invalid request"},"503":{"description":"Delivery API not enabled"}}}},"/api/v1/image/generate":{"post":{"tags":["Image"],"summary":"Generate a static AI image","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerateRequest"}}}},"responses":{"200":{"description":"Image generated"}}}},"/api/v1/image/storyboard-batch":{"post":{"tags":["Mass generation"],"summary":"Render a small photo batch inline (synchronous, unsupervised)","description":"Renders frames and returns them in the response. There is no job id and no QA: use this only for batches small enough to finish inside one request. continuityMode=\"chain\" (the default) renders one frame at a time, conditioning each frame on the previous frame's output, so its ceiling is much lower than the parallel modes. Requests above the ceiling are rejected with 413 BEFORE any credit is charged and carry the durable path in durable_alternative. For genuine mass generation, or for anything that must meet a quality standard, use the supervised path: storyboard-images/plan then storyboard-images/generate. Feature-flagged (STORYBOARD_PHOTO_BATCH_ENABLED).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryboardPhotoBatchRequest"}}}},"responses":{"200":{"description":"status=completed when every frame rendered, status=partial when some failed. Failed frames are refunded."},"402":{"description":"Insufficient credits; nothing was dispatched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Insufficient scope or forbidden project"},"413":{"description":"Batch cannot finish synchronously. no_credits_spent=true; durable_alternative names the supervised endpoints to use instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchOverCapacityResponse"}}}},"429":{"description":"Rate limit exceeded; retry_after_seconds returned"},"503":{"description":"Storyboard photo batch not enabled"}}}},"/api/v1/projects/{projectId}/film-intelligence/storyboard-images/plan":{"post":{"tags":["Mass generation"],"summary":"Compile the authoritative work plan for a supervised image batch","description":"Returns the single authority for what will be generated, what it will cost, and what is missing: every required frame, the reference plates it depends on, the resolved provider, the credit ceiling, and any blocker that would stop execution. Spends no credits. Call this before generate to see the full cost and the blocker list.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Work plan with per-frame requirements, credit ceiling and blockers"},"403":{"description":"Forbidden project"},"404":{"description":"Project or storyboard not found"},"409":{"description":"Script revision conflict: the storyboard is stale against its source revision"}}}},"/api/v1/projects/{projectId}/film-intelligence/storyboard-images/generate":{"post":{"tags":["Mass generation"],"summary":"Start a durable, supervised image batch","description":"The supervised mass-generation entry point, and the one to build on. Persists a job before dispatching, so the batch survives client disconnects and process restarts. Execution is lease-exclusive: a duplicate delivery of the same task cannot make one job run twice. After rendering, every frame is scored against its requirements and failures enter a bounded repair loop with a per-requirement attempt limit, a per-shot credit ceiling and an escalation ladder that ends in human review rather than unbounded retries. Requires expectedExecutionManifestArtifactHash: call plan first and copy executionManifestArtifact.artifactHash from its response. Without it this returns 400 storyboard_image_execution_manifest_required — the hash pins execution to the exact plan that was priced, so a stale plan cannot be executed silently. Returns 202 with a job to poll (job.id, then GET film-intelligence/jobs/{jobId}) — unless every selected requirement was already satisfied by a prior call, in which case it returns 200 with accepted=false and no job: check accepted before assuming a job started.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Recommended. Job identity is content-addressed, so a replayed request returns the existing job instead of starting a second one."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryboardImageGenerateRequest"}}}},"responses":{"200":{"description":"Idempotent no-op: every selected requirement was already satisfied by a prior call. accepted=false, no job, nothing charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryboardImageGenerateAlreadySatisfied"}}}},"202":{"description":"Job persisted and enqueued. The polling handle is job.id (nested), not a top-level jobId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryboardImageGenerateAccepted"}}}},"402":{"description":"Insufficient credits for the plan ceiling; nothing was dispatched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Forbidden project"},"404":{"description":"Project or storyboard not found"},"409":{"description":"Script revision conflict, or the storyboard already has an active job"},"422":{"description":"Plan has blockers that must be resolved before generation"}}}},"/api/v1/projects/{projectId}/film-intelligence/jobs/{jobId}":{"get":{"tags":["Mass generation"],"summary":"Poll a durable generation job","description":"Authoritative job state. status is queued, running, completed, partially_completed or failed. completed means every required frame was rendered AND passed review; partially_completed reports which requirements still failed and whether the batch is resumable. Safe to poll from any client, including one that did not start the job.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job state, per-requirement results and QA evidence"},"403":{"description":"Forbidden project"},"404":{"description":"Job not found"}}}},"/api/v1/projects/{projectId}/film-intelligence/photo-sequences/{planId}":{"get":{"tags":["Mass generation"],"summary":"Read a photo sequence plan and its current lifecycle","description":"The plan, its frames and where it currently stands. Spends nothing. Use it to price a repair before authorizing one, and to see the lifecycle without mutating anything.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"planId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Plan, frames and lifecycle"},"403":{"description":"Forbidden project"},"404":{"description":"Plan not found"}}}},"/api/v1/projects/{projectId}/film-intelligence/photo-sequences/{planId}/review":{"post":{"tags":["Mass generation"],"summary":"Record a human accept/repair decision per frame","description":"This is the human authority step, NOT the automatic scorer. Automatic scoring runs inside the generation job, and its verdicts and evidence are read from film-intelligence/jobs/{jobId} — not here. This endpoint records what a person decided about each frame, so it requires a decisions array (frameIndex, accept|repair, a note, optional prompt additions) and an existing QA report for the plan. Calling it without decisions returns 400, and with no prior QA report returns 409.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"planId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhotoSequenceReviewRequest"}}}},"responses":{"201":{"description":"Decisions recorded; the plan lifecycle advances to reflect them"},"400":{"description":"No decisions supplied, or a decision failed validation"},"403":{"description":"Forbidden project"},"404":{"description":"Plan not found"},"409":{"description":"No QA report exists yet for this plan; generate and let scoring run first"}}}},"/api/v1/projects/{projectId}/film-intelligence/photo-sequences/{planId}/repair":{"post":{"tags":["Mass generation"],"summary":"Repair only the frames that failed review","description":"Regenerates the failing requirements and nothing else, so accepted frames are frozen rather than re-rolled. Bounded by attempts per requirement, requests per shot and a credit ceiling; each escalation tightens constraints before falling back to a frozen prompt, and exhausting the ladder returns human_review instead of spending more.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"planId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Repair job accepted; poll for the new verdicts"},"402":{"description":"Repair would exceed the authorized credit ceiling","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Forbidden project"},"404":{"description":"Plan not found"},"409":{"description":"Repair budget or attempt ladder exhausted; human review required"}}}},"/api/v1/production/capabilities":{"get":{"tags":["Mass generation"],"summary":"What this deployment can actually execute right now","description":"Runtime capability truth, not documentation. Each capability reports configured plus the honest limitations that apply, so a client (or an agent) can check whether a workload is executable before spending anything. Unconfigured providers are reported as unavailable rather than failing at dispatch.","responses":{"200":{"description":"Capability list with configured flags and limitations"}}}},"/api/v1/music":{"post":{"tags":["Music"],"summary":"Compose an original AI song","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MusicGenerateRequest"}}}},"responses":{"200":{"description":"Music generated and URL returned"}}}},"/api/v1/audio/tts":{"post":{"tags":["Audio"],"summary":"Convert text to a neural voice","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtsRequest"}}}},"responses":{"200":{"description":"Audio generated and URL returned"}}}},"/api/v1/music/generate":{"post":{"tags":["Music"],"summary":"Generate music via async orchestration pipeline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MusicGenerateRequest"}}}},"responses":{"202":{"description":"Music generation accepted"}}}},"/api/v1/tts":{"post":{"tags":["Audio"],"summary":"Text-to-speech (legacy alias)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtsRequest"}}}},"responses":{"200":{"description":"Audio generated and URL returned"}}}},"/api/v1/download/{jobId}":{"get":{"tags":["Status"],"summary":"Resolve final downloadable URL for a project or orchestrator job","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Final asset URL payload"}}}},"/api/v1/storage/upload-url":{"post":{"tags":["Storage"],"summary":"Get a signed URL for direct S3 upload","description":"Issues a short-lived upload URL under the authenticated user prefix. Category limits: PHOTOS 20 MB, VIDEOS 500 MB, MUSIC/SFX/VOICES 100 MB.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadUrlRequest"}}}},"responses":{"200":{"description":"Presigned URL returned, including maxBytes for the resolved category"},"400":{"description":"Invalid category, contentType, or sizeBytes"},"401":{"description":"Unauthorized"},"413":{"description":"File exceeds category size limit"}}}},"/api/v1/storage/assets":{"get":{"tags":["Storage"],"summary":"List assets available in Creative Hub library (videos, photos, music, voices)","responses":{"200":{"description":"Asset library grouped by type"}}}},"/api/v1/projects":{"get":{"tags":["Projects"],"summary":"List user projects","responses":{"200":{"description":"Project list"}}},"post":{"tags":["Projects"],"summary":"Create a project","responses":{"200":{"description":"Project created"}}}},"/api/v1/credits/summary":{"get":{"tags":["Credits"],"summary":"Get current user credit summary (stripe + bonus + total)","responses":{"200":{"description":"Credit summary payload"}}}},"/api/v1/video/orchestrate":{"post":{"tags":["Video"],"summary":"Create an orchestrated multimodal video job","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoStartRequest"}}}},"responses":{"202":{"description":"Job started"}}}},"/api/v1/music/status/{jobId}":{"get":{"tags":["Music"],"summary":"Check generated music status by job id","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Music status payload"}}}},"/api/v1/video/quality-check/{jobId}":{"get":{"tags":["Video"],"summary":"Run AI quality director review for a video project","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Quality coherence report payload"}}}},"/api/v1/video/status/{jobId}":{"get":{"tags":["Video"],"summary":"Check generated video status by job id","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Video status payload"}}}},"/api/v1/jobs/{jobId}":{"get":{"tags":["Status"],"summary":"Get async job status and progress","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current status"}}}},"/api/v1/user/settings/creative":{"get":{"tags":["User"],"summary":"Get user creative-agent personalization settings","responses":{"200":{"description":"Creative profile payload"}}},"put":{"tags":["User"],"summary":"Update user creative-agent personalization settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreativeAgentSettingsRequest"}}}},"responses":{"200":{"description":"Creative profile saved"}}}}},"x-myeq-product":{"schemaVersion":"2026-07-30","category":"Audiovisual production infrastructure for AI agents","maturity":"foundation","availability":"internal","productComplete":false,"manifest":"/api/v1/product/manifest","canonicalResources":["Workspace","Project","Asset","Entity","ProductionBible","Storyboard","Plan","Run","Shot","Attempt","Evidence","Approval","RepairPlan","Certificate","Delivery","LedgerEntry"]}}