Production API overview
The HTTP API exposes the same provider-neutral production authority used by MYEQ Studio.
The public documentation is shareable, but API and MCP capability availability is governed by the live product manifest and account access. Foundation or experimental operations are not stability promises.
One lifecycle
Context → Plan → Preflight → Execute → Inspect → Decide → Repair → Certify → Deliver is the long-lived semantic model. Not every stage is currently stable; read the live product manifest before assuming availability.
Plan before spending
Planning compiles creative intent into an inspectable proposal. It should not dispatch paid generation. Preflight then verifies access, references, capabilities and budget.
curl -X POST https://myeq.pro/api/v1/production/plans \
-H "Authorization: Bearer $MYEQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "project-123",
"script": "Create a 60-second vertical trailer",
"vertical": "ai_film",
"sourceLanguage": "en",
"responseLanguage": "es",
"dialogueLanguage": "es",
"visualPromptLanguage": "en"
}'Execution is durable
Paid execution returns durable authority owned by MYEQ. A client disconnect must not cancel or duplicate accepted work. Read job status instead of depending on the caller process staying alive.
Public contracts are provider-neutral
Clients choose production intent and MYEQ capabilities, not private deployment runtimes or retired provider names. Implementation details stay behind adapters.
24, 30 and 60 FPS in Studio, API and MCP
Use the same committed scene snapshot and exact admission across all three interfaces. Requested FPS is preserved; there is no automatic fallback to 24 FPS. Availability depends on the approved worker and the exact scene.
START/END canvases: 704×1280, 1280×704 or 960×960. I2V accepts generated audio or no audio; A2V requires authorized source audio and preserves its selected offset. Ingredients and V2V do not gain high FPS support from this table. Seeds are integers from 0 to 2147483647. I2V and A2V support END without START at 24, 30 and 60 FPS only when the deployed service explicitly admits it. END guides the final frame; the beginning is generated from the prompt. Leave start empty and keep the image in end. This does not promise identical pixels or reverse the video. A2V always needs authorized source audio and at least one START or END image; audio alone is not admitted.
| FPS | Admitted class | Physical limits |
|---|---|---|
| 24 | Default; selected modality must pass its own admission | Duration, audio and references depend on the selected native class |
| 30 | Approved I2V / A2V only | 720p · 2–10 whole seconds · 9:16 / 16:9 / 1:1 · I2V/A2V: START and/or END; A2V also requires source audio |
| 60 | Approved I2V / A2V only | 720p · 2–10 whole seconds · 9:16 / 16:9 / 1:1 · I2V/A2V: START and/or END; A2V also requires source audio |
Save, preflight the quote, then confirm one scene
Create or read the authorized project, commit the scene with PATCH expectedVersion, then send the same snapshot and targetSceneId to /api/v1/production/snapshots/preflight-scene. Inspect data.ready, issues and estimatedCredits; this creates no job or credit reservation. Generate through /api/v1/production/snapshots/generate-scene with confirm=true and a stable Idempotency-Key. Poll the returned jobId. MCP uses myeq.video.preflight_scene and myeq.video.generate_scene with the same snapshot; paid submission never retries automatically. Scene settings override project defaults; preserve matching frozen sceneContracts.
Legacy /video/start, /video/create, /video/create-job and /video/preflight are retired: default/24 returns 410; 30/60 requires snapshot migration with 422. 25/48/50 are unsupported. Preflight failure never changes cadence or charges credits. A successful check does not reserve availability or wallet balance.
const base = process.env.MYEQ_BASE_URL || 'https://myeq.pro';
const headers = { Authorization: 'Bearer ' + process.env.MYEQ_API_KEY, 'Content-Type': 'application/json' };
async function api(path, method, body, extra = {}) {
const response = await fetch(base + path, { method, headers: { ...headers, ...extra },
...(body === undefined ? {} : { body: JSON.stringify(body) }) });
const value = await response.json();
if (!response.ok) throw new Error(JSON.stringify(value));
return value;
}
const project = await api('/api/v1/projects', 'POST', { title: '60 FPS', aspectRatio: '9:16', duration: 4 });
const sourceAudioUrl = process.env.SOURCE_AUDIO_URL;
const generationInputs = { videoProvider: 'myeq_v2', videoModelSelection: 'myeq_v2',
inputModality: sourceAudioUrl ? 'audio_to_video' : 'image_to_video', durationSeconds: 4,
fps: 60, outputResolution: '720p', includeAudio: Boolean(sourceAudioUrl), seed: 12345,
...(sourceAudioUrl ? { sourceAudioUrl, sourceAudioStartTime: 0 } : {}) };
const scene = { id: 'scene-1', prompt: 'A slow camera move. Preserve the subject.',
settings: { fps: 60, durationSeconds: 4 },
start: process.env.START_URL ? [{ name: 'START', url: process.env.START_URL }] : [],
end: process.env.END_URL ? [{ name: 'END', url: process.env.END_URL }] : [], context: [], avatar: [] };
const snapshot = { id: crypto.randomUUID(), version: 1, projectId: project.id,
ownerId: project.ownerUserId, sourceEditorStateVersion: project.version + 1,
createdAt: new Date().toISOString(), projectTitle: project.title,
aspectRatio: '9:16', resolution: '720p', durationSeconds: 4, fps: 60,
generationInputs, scenes: [scene], avatars: [], assetsSummary: [],
sourceAudio: sourceAudioUrl ? { url: sourceAudioUrl, durationSeconds: null } : null, provenance: { source: 'ui' } };
await api('/api/v1/projects/' + project.id, 'PATCH', { expectedVersion: project.version,
editorState: { ...project.editorState, generationInputs,
sceneStoryboard: { scenes: [scene] }, productionSnapshot: snapshot } });
const input = { snapshot, targetSceneId: scene.id };
const quote = await api('/api/v1/production/snapshots/preflight-scene', 'POST', input);
console.log(quote);
if (quote.data?.ready && process.env.CONFIRM_PAID === 'true') {
const idempotencyKey = process.env.SAVED_IDEMPOTENCY_KEY;
if (!idempotencyKey) throw new Error('Persist one stable key before submitting');
const result = await api('/api/v1/production/snapshots/generate-scene', 'POST',
{ ...input, confirm: true }, { 'Idempotency-Key': idempotencyKey });
console.log(result);
const jobId = result.data?.pendingTake?.orchestrationJobId || result.data?.asset?.metadata?.jobId;
if (jobId) console.log(await api('/api/v1/production/jobs/' + encodeURIComponent(jobId), 'GET'));
}