Visão geral da Production API
A API HTTP expõe a mesma autoridade de produção neutra de provider usada pelo Studio.
A documentação é pública, mas a disponibilidade de API/MCP depende do manifesto vivo e do acesso da conta. Foundation ou experimental não significa estabilidade.
Um único ciclo
Context → Plan → Preflight → Execute → Inspect → Decide → Repair → Certify → Deliver é o modelo semântico. Consulte o manifesto vivo.
Planeje antes de gastar
O plano cria uma proposta inspecionável sem despacho pago; Preflight valida acesso, referências, capacidades e orçamento.
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"
}'Execução é durável
Trabalho aceito continua sob MYEQ após desconexão do cliente. Consulte o job.
Contratos públicos são provider-neutral
Clientes escolhem intenção e capacidades MYEQ, não runtimes privados.
24, 30 e 60 FPS no Studio, API e MCP
As três interfaces usam o mesmo snapshot confirmado da cena e a mesma admissão. Os FPS solicitados são preservados; não há mudança automática para 24. A disponibilidade depende do worker aprovado e da cena exata.
Telas START/END: 704×1280, 1280×704 ou 960×960. I2V admite áudio gerado ou sem áudio; A2V exige áudio de origem autorizado e preserva o deslocamento escolhido. Esta tabela não habilita FPS altos para ingredientes nem V2V. Seeds são inteiros de 0 a 2147483647. I2V e A2V admitem END sem START a 24, 30 e 60 FPS apenas se o serviço instalado autorizar explicitamente. END guia o último fotograma; o início é gerado pelo prompt. Deixe start vazio e mantenha a imagem em end. Isto não garante píxeis idênticos nem inverte o vídeo. A2V exige sempre áudio de origem autorizado e pelo menos uma imagem START ou END; só áudio não é admitido.
| FPS | Classe admitida | Limites físicos |
|---|---|---|
| 24 | Padrão; a modalidade escolhida exige admissão própria | Duração, áudio e referências dependem da classe nativa |
| 30 | Somente I2V / A2V aprovados | 720p · 2–10 segundos inteiros · 9:16 / 16:9 / 1:1 · I2V/A2V: START e/ou END; A2V também exige áudio de origem |
| 60 | Somente I2V / A2V aprovados | 720p · 2–10 segundos inteiros · 9:16 / 16:9 / 1:1 · I2V/A2V: START e/ou END; A2V também exige áudio de origem |
Salvar, conferir o preço e confirmar uma cena
Crie ou leia o projeto autorizado, salve a cena com PATCH expectedVersion e envie o mesmo snapshot e targetSceneId para /api/v1/production/snapshots/preflight-scene. Confira data.ready, issues e estimatedCredits; nenhum job ou reserva de créditos é criado. Gere em /api/v1/production/snapshots/generate-scene com confirm=true e Idempotency-Key estável, depois consulte o jobId. MCP usa myeq.video.preflight_scene e myeq.video.generate_scene com o mesmo snapshot; o envio pago nunca é repetido automaticamente. Ajustes da cena prevalecem sobre padrões globais; preserve sceneContracts confirmados correspondentes.
As rotas antigas /video/start, /video/create, /video/create-job e /video/preflight foram retiradas: padrão/24 retorna 410; 30/60 exige migração para snapshot com 422. 25/48/50 não são suportados. Falhas de preflight não mudam FPS nem cobram créditos. Uma verificação aprovada não reserva disponibilidade nem saldo.
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'));
}