Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
API REST

Jobs

Consulte status e resultados de jobs, leia dicas de falha e créditos, verifique 100 jobs em uma chamada, cancele jobs e pare ou continue o Gerar vídeo Pro.

Um job é uma unidade de geração no Nodaro: uma imagem, uma renderização de vídeo, um clipe de fala. A execução de um nó retorna o ID de um job, e uma execução de workflow cria um job para cada nó de IA. Os endpoints de jobs informam o status, o progresso, o resultado e os créditos de cada job. Você consulta um job periodicamente até ele chegar a completed, failed ou cancelled e, depois, lê o resultado em output_data.

Endpoints

MétodoCaminhoO que faz
GET/v1/jobs/:id/statusO status enxuto para a consulta periódica: status, progresso, resultado e erro.
GET/v1/jobs/:idO job completo, incluindo o que foi enviado (input_data) e os créditos.
GET/v1/jobsOs seus jobs, dos mais recentes para os mais antigos, em páginas.
GET/v1/jobs/status?ids=…O status de até 100 jobs, com os IDs na query string.
POST/v1/jobs/batch-statusO status de até 100 jobs, com os IDs no corpo.
POST/v1/jobs/:id/cancelCancela um job e libera os créditos reservados para ele.
DELETE/v1/jobs/:idExclui um job e a mídia privada que ele produziu.
GET/v1/component/execute/:jobId/wait-limitQuanto tempo o servidor espera por uma execução de componente.
POST/v1/generate-video-pro/:jobId/stopInterrompe uma execução do Gerar vídeo Pro (Generate Video Pro) e mantém os segmentos concluídos.
POST/v1/generate-video-pro/continueContinua uma execução do Gerar vídeo Pro como um novo job.
POST/v1/credits/video-pro-estimateCalcula o preço de uma execução do Gerar vídeo Pro sem iniciá-la.

Um token OAuth precisa do escopo jobs:read para ler jobs. Tokens de API pessoais não precisam de escopo.

Ler um job

curl -s https://app.nodaro.ai/v1/jobs/0f1a9c2e-5b7d-4e8a-9c31-6d2f8b4a7e10/status \
  -H "Authorization: Bearer $NODARO_API_KEY"
{
  "data": {
    "id": "0f1a9c2e-5b7d-4e8a-9c31-6d2f8b4a7e10",
    "status": "completed",
    "progress": 100,
    "output_data": { "imageUrl": "https://…/0f1a9c2e.png" },
    "error_message": null,
    "error_hint": null,
    "credit_status": "committed"
  }
}
const { data } = await client.jobs.getStatus(jobId)
if (data.status === 'completed') console.log(data.output_data)

// The full record, with input_data and credits:
const { data: job } = await client.jobs.get(jobId)
nodaro jobs get 0f1a9c2e-5b7d-4e8a-9c31-6d2f8b4a7e10 --json

GET /v1/jobs/:id/status foi feito para loops de consulta periódica: ele omite input_data e os campos de custo, por isso é mais leve que GET /v1/jobs/:id. Os dois respondem { "data": … }, e os dois respondem 404 para um job que não existe ou não é seu. Os campos dos jobs usam snake_case, do jeito que o servidor os envia.

CampoSignificado
idO ID do job.
statusEm que ponto o job está. Veja Status dos jobs.
progressDe 0 a 100.
output_dataO resultado. Os jobs de mídia trazem imageUrl, videoUrl ou audioUrl, muitas vezes com thumbnailUrl. Os outros jobs trazem campos próprios, como text ou json.
error_messagePor que o job falhou, em palavras.
error_hintUm motivo estruturado para dois tipos de falha. Veja Por que um job falhou.
credit_statusreserved, committed, refunded ou null. Veja Créditos de um job.
recoveringtrue enquanto a plataforma repara um job cujo worker parou depois que o modelo já tinha entregado o resultado.
input_dataSó no job completo. O que foi enviado, depois das correções: por exemplo, o prompt final, o seu próprio userPrompt e os IDs de direction.
creditsSó no job completo. Os créditos do job.
job_type, source, source_detailSó no job completo. O tipo de job e de onde ele veio: source é internal, mcp, app, cli, sdk, extension, web ou api, e source_detail indica o cliente, como sdk/1.10.0.
created_at, started_at, completed_atSó no job completo. Carimbos de data e hora.

input_data e output_data são visões públicas: os campos que existem só para o servidor são removidos para todos os chamadores.

Status dos jobs

StatusFinalSignificado
pending, queued, processingNãoO job está aguardando a execução ou em execução.
pending_reviewNãoO resultado existe, e a implantação o retém para uma revisão humana. Continue consultando periodicamente.
completedSimO resultado está em output_data.
failedSimerror_message e error_hint dizem por quê.
cancelledSimVocê ou a plataforma cancelou o job.

Jobs em recuperação. Quando um worker para depois que o modelo já entregou o resultado, o job fica em processing com recovering: true enquanto a plataforma o repara. Depois, ele é concluído ou reembolsado por conta própria. Em modelos lentos, isso pode levar dezenas de minutos, mais do que a espera padrão do SDK. Um JobTimeoutError de runAndWait não cancela o job, então busque o job de novo mais tarde.

Jobs retidos para revisão. Em uma implantação que registra uma política de revisão, um job pode entrar em pending_review. O trabalho está feito, os créditos continuam reserved durante toda a retenção, e uma pessoa decide se o resultado é liberado. O job então termina como completed (aprovado), failed com uma dica policy-block (rejeitado) ou cancelled. Um job retido pode ser cancelado como qualquer job em andamento. Não envie a requisição de novo, porque uma duplicata também ficaria retida. Quando a implantação define um prazo de revisão, um job que ninguém revisa a tempo é rejeitado: ele termina como failed, a reserva é reembolsada e o resultado retido é excluído. Um job retido nunca é aprovado automaticamente. O runAndWait do SDK lança JobHeldError na primeira consulta periódica que encontra pending_review, e o --watch da CLI sai com o código 3.

Boas práticas de consulta periódica

  • Consulte periodicamente a cada 2 a 5 segundos. Um job muda de estado em segundos, não em milissegundos.
  • As leituras de status não contam para o limite de taxa do token. Só as execuções e as listagens de workflows contam para o limite por minuto de um token de API pessoal. Veja Limites de taxa.
  • Acompanhe muitos jobs com uma chamada. Use os endpoints em lote em vez de uma requisição por job.
  • Deixe o cliente esperar por você. O client.nodes.runAndWait do SDK consulta periodicamente a cada 2 segundos por até 15 minutos, e o --watch da CLI consulta periodicamente até o job terminar.

Por que um job falhou

A tabela de erros em Erros cobre as requisições que nunca criaram um job. Um job que falha depois traz error_message e, em dois tipos de falha, também um error_hint estruturado.

O filtro de segurança de um modelo bloqueou a requisição:

{ "kind": "safety-block", "class": "safety", "retried": true, "suggestedProvider": "nano-banana-pro" }
  • class é copyright, likeness ou safety. Um bloqueio copyright ou likeness é definitivo: a mesma requisição nunca passa.
  • Em alguns modelos, um filtro safety nem sempre é consistente. No GPT Image 2, no GPT Image 2.5 Flare e no GPT Image 2.5 Sunburst, o Nodaro tenta a mesma requisição de novo uma vez, sem custo extra. retried informa se essa nova tentativa já aconteceu.
  • suggestedProvider só aparece quando o modelo tem uma alternativa recomendada. É um ID de modelo real: envie o mesmo prompt e as mesmas referências para ele.

A política de uma implantação rejeitou o job:

{ "kind": "policy-block", "policyId": "brand-safety", "reason": "This image was not approved for release.", "hookPoint": "result" }
  • reason é um texto escrito para o seu usuário pela política da implantação. Mostre esse texto como está.
  • hookPoint é request quando o job foi recusado antes de ser executado, e result quando o resultado dele foi rejeitado depois, inclusive por um revisor.
  • A plataforma não tenta de novo depois de uma rejeição por política e não oferece outro modelo.

Nenhuma outra falha tem error_hint. Quando um modelo recusa a própria requisição, porque as configurações ou a mídia de entrada são inválidas para esse modelo, error_message informa isso: mude as configurações ou a mídia antes de executar de novo. Um erro do lado do modelo continua valendo uma nova tentativa, seja qual for o texto. error_hint aparece em todo payload de job que traz error_message: o job completo, as rotas de status, a lista e as duas rotas em lote.

Créditos de um job

credit_status acompanha a reserva de créditos do job:

ValorSignificado
reservedOs créditos ficam reservados enquanto o job é executado.
committedO job entregou o resultado e foi cobrado.
refundedA reserva foi liberada, por exemplo, depois de um bloqueio de segurança.
nullO job não tem um registro de créditos para informar.

Ele aparece em GET /v1/jobs/:id, GET /v1/jobs/:id/status e GET /v1/jobs/status, nunca em GET /v1/jobs nem em POST /v1/jobs/batch-status. Uma geração que termina em um bloqueio de segurança ou de política é sempre reembolsada. A rara exceção é um job cujos créditos já tinham sido liquidados antes de uma política rejeitar o resultado dele. Veja Créditos.

Listar os seus jobs

GET /v1/jobs retorna os seus jobs, dos mais recentes para os mais antigos, como { data: Job[], next }:

Parâmetro de consultaSignificado
limitTamanho da página, até 100.
cursorO valor next da página anterior.
typeA rota que criou o job, com o valor exato, como llm-structured ou video-analysis.
originO app cliente que enviou o job, com o valor exato, como studio.
attachToCharacterIdOs jobs de um personagem. Veja Personagens.

type e origin podem ser combinados. Uma página pode ter menos linhas que limit, até nenhuma, e ainda trazer um next: continue paginando enquanto next estiver presente, nunca contando linhas.

const { data: runs, next } = await client.jobs.list({ type: 'llm-structured', origin: 'my-app' })

Consultar periodicamente muitos jobs de uma vez

Dois endpoints retornam o status de até 100 jobs em uma única ida e volta:

curl -s "https://app.nodaro.ai/v1/jobs/status?ids=$JOB_A,$JOB_B,$JOB_C" \
  -H "Authorization: Bearer $NODARO_API_KEY"
{
  "jobs": [
    { "id": "0f1a9c2e-…", "status": "completed", "output_data": { "imageUrl": "https://…/a.png" }, "error_message": null, "error_hint": null, "credit_status": "committed" },
    { "id": "7d3e5f60-…", "status": "processing", "output_data": null, "error_message": null, "error_hint": null, "credit_status": "reserved" }
  ]
}
curl -s -X POST https://app.nodaro.ai/v1/jobs/batch-status \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"jobIds\": [\"$JOB_A\", \"$JOB_B\", \"$JOB_C\"]}"

A resposta é { "data": [ … ] }, com id, status, output_data, error_message e error_hint para cada job, e sem credit_status.

Os IDs que não existem, ou que pertencem a outra pessoa, ficam de fora sem erro. Compare a resposta com a sua própria lista de IDs.

Cancelar ou excluir um job

POST /v1/jobs/:id/cancel cancela um job e libera os créditos que ele reservou. A resposta é { "success": true, "cancelled": 1 }. Um job retido em pending_review também pode ser cancelado.

DELETE /v1/jobs/:id exclui um job e a mídia privada que ele produziu, e responde { "success": true }. Só o dono do job pode excluí-lo. Um job em execução é excluído do jeito que está, então cancele-o antes quando o trabalho dele precisar parar.

curl -s -X POST https://app.nodaro.ai/v1/jobs/$JOB_ID/cancel \
  -H "Authorization: Bearer $NODARO_API_KEY"
const { cancelled } = await client.jobs.cancel(jobId)
await client.jobs.delete(jobId)
nodaro jobs cancel 0f1a9c2e-5b7d-4e8a-9c31-6d2f8b4a7e10

Para interromper uma execução de workflow inteira, cancele essa execução: veja Execuções.

Execuções de componentes

POST /v1/component/execute executa um Componente (Component) salvo em segundo plano e responde 202 com { jobId }. Consulte esse job periodicamente, como qualquer outro. O servidor dá 90 minutos a uma execução de componente, mais o orçamento de tempo de qualquer renderização longa dentro dela, como a renderização final de um nó Aplicar EDL (Apply EDL).

Um cliente com um limite de tempo próprio pode perguntar quanto tempo o servidor vai esperar:

curl -s https://app.nodaro.ai/v1/component/execute/$JOB_ID/wait-limit \
  -H "Authorization: Bearer $NODARO_API_KEY"
{ "data": { "budgetExcessMs": 0, "waitLimitMs": 5400000, "pendingBudgetedNodes": true } }
  • waitLimitMs é a espera do servidor para esta execução: 90 minutos mais budgetExcessMs.
  • budgetExcessMs fica em 0 até a execução iniciar uma renderização longa.
  • pendingBudgetedNodes é true enquanto uma renderização longa ainda não começou e enquanto a própria execução ainda não começou. Por isso, um excesso 0 ainda não significa que não há nada longo dentro dela.

Os dois valores podem mudar durante a execução, então pergunte de novo quando waitLimitMs for atingido. A rota só responde ao dono da execução, com 404 para qualquer outra pessoa e para jobs que não são execuções de componentes. O próprio editor usa esta regra: espera 30 minutos por uma execução sem nada longo dentro, waitLimitMs depois que uma renderização longa começa e pelo menos 90 minutos enquanto pendingBudgetedNodes é true. Depois, pergunta de novo.

Execuções do Gerar vídeo Pro

O Gerar vídeo Pro faz vídeos longos um segmento por vez e salva o progresso entre os segmentos, então uma execução pode ser interrompida e continuada depois. Ele roda no Nodaro Cloud, e uma instalação self-hosted o executa pela conexão com o Nodaro Cloud.

Interromper uma execução

POST /v1/generate-video-pro/:jobId/stop interrompe de forma controlada uma execução em processing:

  • O segmento que está sendo gerado é abandonado e, mesmo assim, é cobrado, porque o modelo continua a renderizá-lo.
  • Os segmentos restantes são pulados.
  • Todos os segmentos concluídos são unidos no vídeo final do job.
  • A parte não usada da reserva é reembolsada.

A resposta é { "jobId": "…", "stopping": true }. Continue consultando o job periodicamente: ele termina como completed, com output_data.pro.stopped igual a true e com stoppedAtSegment. Já um job que ainda está em pending é cancelado com reembolso total.

Continuar uma execução

POST /v1/generate-video-pro/continue inicia um novo job a partir de um job terminado. Ele reaproveita o plano do job original e todos os segmentos entregues antes de fromSegment, e gera de novo a partir dali:

{ "fromJobId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", "fromSegment": 4 }
  • fromSegment começa em 1. Por padrão, é o primeiro segmento que não foi entregue.
  • O job original precisa estar terminado: interrompido, com falha e pelo menos um segmento entregue, ou concluído. Um fromSegment explícito em uma execução concluída gera o final dela de novo.
  • Você paga só pelos segmentos gerados de novo, mais a taxa fixa do Gerar vídeo Pro.
  • A rota respeita o cabeçalho Idempotency-Key, então uma requisição repetida não inicia um segundo job.

A resposta é { jobId, continuedFromJobId, fromSegment, segmentCount }. Consulte periodicamente o novo jobId.

curl -s -X POST https://app.nodaro.ai/v1/generate-video-pro/$JOB_ID/stop \
  -H "Authorization: Bearer $NODARO_API_KEY"

curl -s -X POST https://app.nodaro.ai/v1/generate-video-pro/continue \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4c1f0a7e-2b3d-4e5f-8a9b-0c1d2e3f4a5b" \
  -d "{\"fromJobId\": \"$JOB_ID\", \"fromSegment\": 4}"
await client.videoPro.stop(jobId)
const { data } = await client.jobs.getStatus(jobId) // completes with a partial video

const { jobId: childId } = await client.videoPro.continueRun(jobId, { fromSegment: 4 })
nodaro video-pro stop 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d
nodaro video-pro continue 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d --from-segment 4 --watch

As duas rotas respondem 404 para um job que não é seu e 400 para um job que não é uma execução do Gerar vídeo Pro.

Estimar uma execução

POST /v1/credits/video-pro-estimate calcula o preço de uma execução do Gerar vídeo Pro sem criar um job nem reservar créditos:

{ "provider": "gemini-omni-flash", "resolution": "720p", "duration": 12, "renderMethod": "keyframes", "segmentMode": "short" }

Em uma configuração de exemplo, a resposta é { "data": { "credits": 760, "upperBound": true } }. Leia a resposta em tempo real para ver os preços atuais.

Prop

Type

  • Com segmentMode short ou long, a execução primeiro atribui ações completas a trechos da origem, e upperBound: true significa que o valor é o limite da reserva antes do planejamento. A cobrança final segue o plano real.
  • Uma estimativa planOnly cobre a taxa de planejamento e retorna upperBound: false. Os valores sourceSegmentDurations e planCheckpoint dela podem ser enviados de volta como sourceSegmentDurations e seedPlan, com o mesmo modo e as mesmas configurações.

Leia Gerar vídeo Pro para saber como a segmentação funciona e o que cada configuração faz.

Perguntas frequentes

Última atualização

Nesta página