# Workflows

> Execute workflows do Nodaro pela API com novas entradas, aguarde ou consulte periodicamente o resultado; liste, crie, atualize, exporte e mova workflows.

Source: https://nodaro.ai/pt-BR/docs/developers/api/workflows

Um **workflow** é um canvas salvo de nós conectados. A API pode executá-lo, passar novos valores de entrada para uma única execução e gerenciá-lo como qualquer outro recurso. Uma execução começa com uma requisição que retorna um `executionId`, e você consulta a execução periodicamente até ela terminar. Uma execução curta também pode aguardar o resultado na mesma requisição.

## Endpoints
### Executar um workflow
| Método | Caminho | O que faz |
| --- | --- | --- |
| `POST` | `/v1/workflows/:id/run` | Executa o workflow salvo, ou alguns dos nós dele. Responde `202` com um `executionId`. |
| `GET` | `/v1/api/workflows` | Lista os workflows que o seu token de API pode executar. Aceita `?limit=` e `?cursor=`. |
| `GET` | `/v1/api/schema?workflowId=…` | Os campos de entrada e as saídas de um workflow, com `estimatedCredits`. |
| `POST` | `/v1/api/run` | Executa um workflow com novos valores de entrada. Adicione `?wait=true&timeout=…` para aguardar o resultado. |
| `GET` | `/v1/api/status/:execId` | O status da execução, as contagens de nós e os créditos usados. |
| `GET` | `/v1/api/result/:execId` | As saídas da execução, quando o status dela for `completed` ou `failed`. |
| `POST` | `/v1/app/:slug/run` | Executa um app publicado com os campos do formulário dele. Veja [Miniapps](https://nodaro.ai/docs/developers/embed/miniapps). |

### Gerenciar workflows
| Método | Caminho | O que faz |
| --- | --- | --- |
| `GET` | `/v1/projects/:projectId/workflows` | Os workflows de um projeto, sem os nós e as conexões. |
| `GET` | `/v1/workflows` | Os seus workflows de todos os projetos. |
| `GET` | `/v1/workflows/:id` | Um workflow com os nós, as conexões e as configurações dele. |
| `POST` | `/v1/projects/:projectId/workflows` | Cria um workflow em um projeto. |
| `PATCH` | `/v1/workflows/:id` | Altera qualquer subconjunto dos campos de um workflow. |
| `DELETE` | `/v1/workflows/:id` | Exclui um workflow. |
| `GET` | `/v1/workflows/:id/export` | Exporta o workflow como um pacote JSON. Adicione `?assets=true` para incluir os personagens, objetos e locais dele. |
| `POST` | `/v1/workflows/import` | Cria um workflow a partir de um pacote. |
| `POST` | `/v1/workflows/:id/move` | Move um workflow para outro projeto. |
| `GET` | `/v1/workflows/shared-with-me` | Os workflows que outras pessoas compartilharam com você. |

O compartilhamento, os colaboradores e as permissões por workflow estão em [Espaços de trabalho e organizações](https://nodaro.ai/docs/developers/api/workspaces).

## Três formas de executar um workflow
| Endpoint | Credencial | Valores de entrada | Use quando |
| --- | --- | --- | --- |
| `POST /v1/workflows/:id/run` | Qualquer token. Tokens OAuth precisam de `workflows:execute`. | Os valores salvos. `nodeIds` executa um subconjunto. | Você executa o workflow como ele está salvo, para a sua conta ou para um usuário OAuth. |
| `POST /v1/api/run` | Um token de API pessoal | `inputs` substitui os valores dos nós de entrada nesta execução. | Um script precisa de valores diferentes a cada execução, ou quer aguardar o resultado. |
| `POST /v1/app/:slug/run` | Qualquer token | Os campos do formulário do app, mais substituições diretas de campos de nós | O workflow está publicado como um app com um formulário com curadoria. |

Os cinco endpoints `/v1/api/` são a via original dos tokens de API. Eles existem desde antes dos apps publicados e continuam com suporte, mas as novas integrações que precisam de entradas costumam publicar o workflow como app e usar `POST /v1/app/:slug/run`. Essa rota recebe os campos do app como um mapa plano em `inputs` e um objeto opcional `inputOverrides`, com substituições diretas no formato `{ nodeId: { field: value } }`. Os dois são mesclados, e `inputOverrides` prevalece em qualquer campo que ambos definam.

## Executar um workflow salvo
`POST /v1/workflows/:id/run` inicia uma execução do workflow como ele está salvo. Envie um corpo vazio para executar todos os nós, ou `nodeIds` para executar um subconjunto:

**curl**

```bash
curl -s -X POST https://app.nodaro.ai/v1/workflows/8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f/run \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```json
{ "executionId": "3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b", "status": "pending" }
```

**TypeScript SDK**

```ts
const { executionId } = await client.workflows.run(workflowId)

// Or run only some nodes:
await client.workflows.run(workflowId, { nodeIds: ['text-prompt-1', 'generate-image-1'] })
```

**CLI**

```bash
nodaro workflows run 8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f --watch
nodaro workflows run 8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f --node text-prompt-1 generate-image-1
```

<TypeTable
type={{
nodeIds: { type: 'string[]', description: 'Opcional. Os ids dos nós a executar. Omita para executar o workflow inteiro.' },
}}
/>

A resposta é `202 Accepted` com `{ executionId, status }`, em que `status` é `pending` ou `running`. Consulte a execução periodicamente com `GET /v1/workflow-executions/:id`, descrito em [Execuções](https://nodaro.ai/docs/developers/api/executions). Com `--watch`, a CLI faz a consulta periódica por você e sai com o código `2` quando a execução falha e `130` quando ela é cancelada.

| Status | Código | Significado |
| --- | --- | --- |
| 402 | `insufficient_credits` | Seus créditos não cobrem o custo da execução no pior caso. |
| 403 | `forbidden` | Você pode ver o workflow, mas não pode executá-lo. Em um espaço de trabalho, para executar é preciso ter acesso de edição e ser um membro ativo. |
| 404 | `not_found` | O workflow não existe, ou você não pode vê-lo. |
| 409 | `already_running` | O workflow já tem uma execução ativa. A resposta traz o `executionId` dessa execução. |

## Executar um workflow com novos valores de entrada
`POST /v1/api/run` recebe um objeto `inputs` que substitui os valores dos nós de entrada somente nesta execução. A autenticação é feita com um token de API pessoal. As chaves de `inputs` são ids de nós ou, por conveniência, rótulos únicos de nós. Dentro de cada chave, informe o campo de entrada do nó, como `text` para um prompt de texto.

Workflow: O workflow de exemplo: um nó Texto, cujo texto a execução pela API substitui, alimenta um nó Gerar imagem.

- Texto → Gerar imagem (prompt)

O exemplo abaixo executa um workflow com um nó [**Texto** (Text)](https://nodaro.ai/docs/nodes/automate/text), de id `text-prompt-1`, conectado a um nó [**Gerar imagem** (Generate Image)](https://nodaro.ai/docs/nodes/image/generate-image).

### Encontrar os campos de entrada
`GET /v1/api/schema` lista as entradas do workflow, com o campo que cada uma recebe, as saídas e uma estimativa dos créditos que uma execução custa:

```bash
curl -s "https://app.nodaro.ai/v1/api/schema?workflowId=$WORKFLOW_ID" \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

```json
{
"workflowId": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"name": "Sunset stills",
"estimatedCredits": 50,
"inputs": [
{ "nodeId": "text-prompt-1", "key": "text", "label": "Prompt", "type": "text" }
],
"outputs": [
{ "nodeId": "generate-image-1", "label": "Generate Image", "type": "image" }
]
}
```

### Iniciar a execução
```bash
curl -s -X POST https://app.nodaro.ai/v1/api/run \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"workflowId": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"inputs": {
"text-prompt-1": { "text": "a cat at sunset" }
}
}'
```

```json
{ "executionId": "3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b", "status": "pending" }
```

### Consultar periodicamente até a execução terminar
`GET /v1/api/status/:execId` retorna o status, as contagens de nós e os créditos usados até o momento. Consulte a execução periodicamente, a cada 2 a 5 segundos, até o status ser `completed`, `failed`, `cancelled`, `timed_out` ou `discarded`.

### Buscar o resultado
`GET /v1/api/result/:execId` retorna as saídas de uma execução `completed` ou `failed`. Para uma execução que terminou como `cancelled`, `timed_out` ou `discarded`, leia o `errorMessage` da resposta de status: essas execuções não têm payload de resultado, e a rota de resultado continua respondendo `202`.

```json
{
"executionId": "3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b",
"status": "completed",
"creditsUsed": 50,
"durationMs": 12450,
"errorMessage": null,
"outputs": [
{
"nodeId": "generate-image-1",
"label": "Generate Image",
"type": "image",
"url": "https://…/output.png"
}
]
}
```

O fluxo completo em um único script, e as mesmas chamadas em TypeScript:

**curl**

```bash
BASE="https://app.nodaro.ai"
WORKFLOW_ID="8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f"

EXEC=$(curl -s -X POST "$BASE/v1/api/run" \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"workflowId\": \"$WORKFLOW_ID\", \"inputs\": {\"text-prompt-1\": {\"text\": \"a cat at sunset\"}}}" \
| jq -r .executionId)

while true; do
STATUS=$(curl -s -H "Authorization: Bearer $NODARO_API_KEY" \
"$BASE/v1/api/status/$EXEC" | jq -r .status)
echo "Status: $STATUS"
case "$STATUS" in completed|failed|cancelled|timed_out|discarded) break;; esac
sleep 5
done

curl -s -H "Authorization: Bearer $NODARO_API_KEY" "$BASE/v1/api/result/$EXEC" | jq .
```

**TypeScript SDK**

```ts
// The /v1/api/ lane has no dedicated SDK method: call it with client.request.
const schema = await client.request('GET', '/v1/api/schema', {
query: { workflowId },
})

const { executionId } = await client.request<{ executionId: string }>('POST', '/v1/api/run', {
body: { workflowId, inputs: { 'text-prompt-1': { text: 'a cat at sunset' } } },
})

const final = ['completed', 'failed', 'cancelled', 'timed_out', 'discarded']
let status = 'pending'
while (!final.includes(status)) {
await new Promise((r) => setTimeout(r, 3_000))
;({ status } = await client.request<{ status: string }>('GET', `/v1/api/status/${executionId}`))
}

const result = await client.request('GET', `/v1/api/result/${executionId}`)
```

A CLI executa workflows somente com os valores salvos. Para passar valores pelo terminal, publique o workflow como app e execute `nodaro apps run <slug> --input prompt="…"`.

<TypeTable
type={{
workflowId: { type: 'string (uuid)', description: 'O workflow a executar.', required: true },
inputs: { type: 'object', description: 'Opcional. Novos valores para os nós de entrada, com chaves pelo id do nó ou por um rótulo único de nó. Cada valor é um objeto com os campos daquele nó, por exemplo { text: "…" }.' },
}}
/>

Um token com escopo de workflow só pode executar os workflows desse escopo. Qualquer outro workflow responde `403 forbidden`. `POST /v1/api/run` e `GET /v1/api/workflows` contam para o limite por minuto do token; as leituras de status, de resultado e de schema não contam. Veja [Limites de taxa](https://nodaro.ai/docs/developers/api/rate-limits).

## Síncrono ou assíncrono
`POST /v1/api/run` é assíncrono por padrão: ele responde na hora `202 Accepted` com `{ executionId, status: "pending" }`, e você consulta a execução periodicamente.

Para um workflow curto, mantenha a conexão aberta até ele terminar:

```http
POST /v1/api/run?wait=true&timeout=120
```

- O servidor verifica a execução a cada 5 segundos por até `timeout` segundos. O padrão é 120, e o máximo é 600.
- Se a execução terminar a tempo, a resposta é o mesmo payload de `GET /v1/api/result/:execId`. O `status` dela é `completed`, `failed`, `cancelled`, `timed_out` ou `discarded`.
- Se não terminar, a resposta é `202` com `{ executionId, status: "pending" }`, e você passa a consultar periodicamente a partir daí.

Use a forma síncrona para execuções que devem terminar em menos de um minuto, como geração de texto e trabalhos leves de imagem. Use a forma assíncrona para workflows que renderizam vídeo ou fazem upscale de vídeo. No SDK, aumente o `timeoutMs` de `createClient` para um valor acima do seu `timeout`, porque o cliente desiste depois de 60 segundos por padrão.

`POST /v1/workflows/:id/run` e as rotas de geração são sempre assíncronos. Para um único nó, o `nodes.runAndWait` do SDK consulta o job periodicamente por você: veja [Executar um único nó](https://nodaro.ai/docs/developers/api/nodes).

## O que uma execução não pode mudar
Uma requisição de execução não pode redirecionar os nós externos (outbound) de um workflow. Para onde um workflow envia dados e de onde ele os busca é decidido pelo próprio workflow, em todos os endpoints de execução, incluindo `POST /v1/workflows/:id/run`, `POST /v1/api/run` e `POST /v1/app/:slug/run`.

Os nós externos são [**Saída de webhook** (Webhook Output)](https://nodaro.ai/docs/nodes/publish/webhook-output) e os nós de publicação em redes sociais, como [**Publicar nas redes** (Publish to Social)](https://nodaro.ai/docs/nodes/publish/publish-to-social). Também são externos os nós de busca, como [**Extrair da web** (Web Scrape)](https://nodaro.ai/docs/nodes/automate/web-scrape), [**Feed de canal do Telegram** (Telegram Channel Feed)](https://nodaro.ai/docs/nodes/automate/telegram-channel-feed) e [**URL de vídeo** (Video URL)](https://nodaro.ai/docs/nodes/automate/video-url). Nesses nós, uma substituição não pode alterar:

- campos cujo nome termina em `Url` ou `Urls`;
- `target`, `targets`, `query`, `channel`, `chatId`, `connectionId`, `credentialId`, `platform`, `webhook`, `endpoint`, `host` ou `privacy`;
- os seletores `actor` e `mode`, que escolhem qual campo de destino o nó de busca lê.

A regra vale para valores aninhados em um objeto ou em uma entrada de `fieldMappings`. Ela vale tanto para um valor vazio quanto para um novo endereço: apagar um destino faria o nó ler, no lugar dele, o texto que vem dos nós anteriores. Uma requisição assim recebe `400 locked_field` antes de qualquer coisa ser executada. O erro nomeia até dez dos campos problemáticos e informa quantos são os demais. Uma substituição aninhada a mais de 32 níveis de profundidade em um nó desses é recusada de imediato.

Os campos comuns desses nós, como uma legenda ou um limite, e os campos de mídia `url` dos nós de entrada, como uploads e áudio de referência, continuam podendo ser substituídos.

## Correções de parâmetros
As rotas de geração de imagem e de vídeo aceitam um único vocabulário para `aspectRatio`, `resolution` e `quality`, qualquer que seja o modelo. Nenhum modelo aceita todos esses valores. Em vez de rejeitar um valor que o modelo escolhido não aceita, o servidor o **corrige** para um valor que o modelo aceita e informa o que mudou. Uma rejeição no meio de um workflow faria falhar todos os nós ao lado dele que já tivessem gerado resultados e sido cobrados.

As rotas que corrigem valores são `POST /v1/generate-image`, `/v1/image-to-image`, `/v1/edit-image`, `/v1/text-to-video` e `/v1/generate-video`:

```json
{
"jobId": "0f1a9c2e-5b7d-4e8a-9c31-6d2f8b4a7e10",
"adjustments": [
{
"field": "aspectRatio",
"from": "3:2",
"to": "auto",
"reason": "GPT Image 2 does not support aspectRatio \"3:2\" — using \"auto\" instead. Supported: auto, 1:1, 16:9, 9:16, 4:3, 3:4."
},
{
"field": "resolution",
"from": "4K",
"to": "1K",
"reason": "GPT Image 2 only renders 1K at the \"auto\" aspect ratio."
}
]
}
```

- **`adjustments` não aparece quando nada mudou.** A resposta de uma requisição válida é exatamente `{ "jobId": "…" }`.
- **`to` não aparece quando o modelo não tem essa configuração** e o valor foi descartado, por exemplo um `aspectRatio` enviado a um upscaler.
- **Os créditos seguem o valor corrigido.** Uma requisição ao [GPT Image 2](https://nodaro.ai/docs/models/image/gpt-image-2) com `auto` em `2K` é renderizada e cobrada em 1K, porque `auto` só renderiza em 1K.
- **Os workflows salvos também são corrigidos.** Um workflow salvo pela API ou pelo MCP recebe as mesmas correções quando é gravado.
- **Os valores aceitos por cada modelo** estão em `GET /v1/models`. Veja [Descobrir modelos](https://nodaro.ai/docs/developers/api/nodes#discover-models).

### Correções nas rotas de vídeo
`/v1/text-to-video` e `/v1/generate-video` retornam `adjustments` no mesmo formato. `/v1/generate-video` também repete o `reason` de cada correção no array `warnings`, junto com avisos que não são sobre parâmetros, como `voice_unsupported_for_provider`. Leia `adjustments` quando precisar saber qual configuração mudou. Os dois nunca divergem.

- **Um valor não aceito vai para a opção mais próxima**, nunca para a mais barata nem para a primeira. Uma requisição `4k` em um modelo que vai até 1080p renderiza em 1080p, não em 480p, e um `9:21` vertical vira `9:16`, não `16:9`.
- **Uma `resolution` omitida é enviada na faixa em que é cobrada.** Quando a plataforma declara a faixa padrão de um modelo, você é cobrado por essa faixa, e é essa faixa que o modelo recebe. O valor aparece no `input_data` do job, então você sempre pode ver o que foi enviado.
- **A grafia é normalizada antes do cálculo do preço.** `4K` é lido como `4k`, então é cobrado e renderizado na faixa 4K.
- **Alguns modelos renderizam uma faixa fixa para qualquer outro valor.** O [MiniMax Hailuo 3](https://nodaro.ai/docs/models/video/minimax-h3) renderiza em 2K tudo o que não for `768P`, e a família [Wan 3.0](https://nodaro.ai/docs/models/video/wan-3-0) renderiza em 720p. Nesses casos, a correção aponta para a faixa que o modelo vai produzir, então o preço corresponde à renderização. A entrada do modelo em `GET /v1/models` declara isso em `unlistedResolutionRendersAs`.
- **`duration` é enviado como você informar**, exceto nos modelos [LTX 2.3](https://nodaro.ai/docs/models/video/ltx-2-3-pro). Eles são cobrados por uma escala fixa de durações por resolução, então uma duração entre dois degraus vai para o degrau mais próximo e é informada em `adjustments`.
- **`duration: -1` significa Automática** nos modelos que oferecem essa opção, a família [Seedance 2](https://nodaro.ai/docs/models/video/seedance-2) (`autoDuration: true` em `GET /v1/models`). O modelo escolhe a duração do clipe, que é a duração do clipe de origem quando ele edita um vídeo de referência. Uma execução com duração Automática reserva créditos para o clipe mais longo do modelo e reembolsa a diferença até a duração entregue. Os outros modelos ignoram `-1` e renderizam na duração padrão.

As rotas de imagem de personagem e de local (`/v1/generate-character`, `/v1/generate-character-asset`, `/v1/generate-location` e `/v1/generate-location-asset`) corrigem `quality` e `resolution` da mesma forma, mas não retornam `adjustments`. O valor corrigido só fica visível no `input_data` do job, em `GET /v1/jobs/:id`.

## Gerenciar workflows
### Listar e ler
`GET /v1/projects/:projectId/workflows` retorna os workflows de um projeto sem `nodes`, `edges` e `settings`. `GET /v1/workflows/:id` retorna um workflow completo. Em uma organização, a lista segue o espaço de trabalho em que você atua: veja [Espaços de trabalho](https://nodaro.ai/docs/developers/api/workspaces).

**curl**

```bash
curl -s https://app.nodaro.ai/v1/projects/$PROJECT_ID/workflows \
  -H "Authorization: Bearer $NODARO_API_KEY" | jq '.data[] | {id, name}'
```

**TypeScript SDK**

```ts
const { data: workflows } = await client.workflows.list({ projectId })
const { data: workflow } = await client.workflows.get(workflows[0].id)
console.log(workflow.nodes.length)
```

**CLI**

```bash
nodaro workflows list --project $PROJECT_ID --json
nodaro workflows get 8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f
```

### Criar e atualizar
Crie um workflow em um projeto com `POST /v1/projects/:projectId/workflows`. Tudo, exceto o projeto, é opcional e usa os padrões do servidor quando omitido:

```ts
const { data: wf } = await client.workflows.create({
projectId,
name: 'My workflow',
nodes: [],
edges: [],
})
```

`PATCH /v1/workflows/:id` altera qualquer subconjunto de campos. Para proteger uma atualização contra uma edição simultânea, envie `expectedVersion`, o inteiro `version` da sua última leitura. Se o workflow mudou desde então, a atualização é recusada com `409 workflow_conflict`, e o erro traz `currentVersion`, `currentUpdatedAt` e `currentRecord`, que é o workflow atual completo. Mescle sua alteração em `currentRecord` e salve de novo, sem uma leitura extra. `expectedUpdatedAt`, um timestamp, funciona do mesmo jeito.

```ts

try {
await client.workflows.update(id, { name: 'Renamed', expectedVersion: 7 })
} catch (err) {
if (err instanceof WorkflowConflictError && err.currentRecord) {
await client.workflows.update(id, { name: 'Renamed', expectedVersion: err.currentVersion })
} else throw err
}
```

- Os valores de estado de execução no `data` de um nó, como o status de execução, o job atual e o progresso, são removidos ao salvar e nunca são armazenados.
- `thumbnailUrl` define a imagem de prévia do workflow a partir de uma imagem já hospedada. `null` remove a imagem.
- Um salvamento que envia só `edges` e conecta uma camada de [**Sobreposição em vídeo** (Video Overlay)](https://nodaro.ai/docs/nodes/video/video-overlay) reescreve esse nó. Por isso, ele responde `409 workflow_conflict` quando o workflow mudou desde a leitura, mesmo sem `expectedVersion`.
- `visibility` é `private` ou `workspace`. Só o criador ou um administrador do espaço de trabalho pode alterá-la, e um workflow fora de um espaço de trabalho responde `400 not_workspace_scoped`.

### Excluir
`DELETE /v1/workflows/:id` exclui um workflow. O criador e um administrador do espaço de trabalho podem excluí-lo; um colaborador, nunca. Excluir um workflow que não existe, ou que você não pode ver, responde `404`, então uma exclusão nunca é um sucesso silencioso. Um colaborador que pode ver o workflow, mas não pode excluí-lo, recebe `403`.

### Exportar e importar
`GET /v1/workflows/:id/export` retorna o workflow como um pacote JSON portátil. Com `?assets=true`, o pacote também leva os personagens, objetos e locais que o workflow usa, se forem seus. Quando os nós apontam para mídias que outra instalação não consegue buscar, como arquivos em `localhost` ou em uma rede privada, o pacote as lista em `portability.unreachableMedia`.

`POST /v1/workflows/import` cria um workflow a partir de um pacote:

```http
POST /v1/workflows/import
{ "projectId": "<project uuid>", "workflow_json": { "version": 1, "name": "…", "nodes": [], "edges": [] } }
```

A importação recria na sua conta os personagens, objetos, criaturas e locais do pacote e faz os nós apontarem para eles. Ela copia as mídias acessíveis para o armazenamento desta instalação: até 25 arquivos para as mídias do workflow e mais 25 para as entidades do pacote, com imagens de até 20 MB e vídeo ou áudio de até 50 MB. A resposta traz o novo workflow e um `importReport`:

| Campo | Significado |
| --- | --- |
| `rehosted` | Quantos arquivos foram copiados para esta instalação. |
| `unreachable` | Mídias em hosts privados, que continuam apontando para onde estavam. Esses nós não são executados até o arquivo ser enviado de novo. |
| `skipped` | Mídias que não puderam ser copiadas, com o motivo, como `HTTP 404`. |
| `assetIdMap` | Cada id de entidade do pacote, mapeado para o registro criado para ela. |
| `assetsSkipped` | Entidades que não couberam na sua cota de armazenamento. O workflow é criado mesmo assim. |

Pela CLI: `nodaro workflows export <id> --with-assets --output bundle.json` e depois `nodaro workflows import bundle.json --project <projectId>`. Leia [Importação e exportação](https://nodaro.ai/docs/guides/import-export) para saber o que é transferido.

### Mover para outro projeto
```http
POST /v1/workflows/:id/move
{ "projectId": "…" }
```

Mover é uma gravação no workflow, então um token OAuth precisa de `workflows:write`. `PATCH /v1/workflows/:id` com um `projectId` faz a mesma coisa e segue as mesmas regras. Você pode mover o trabalho que criou. Dentro de uma organização, um administrador de espaço de trabalho também pode mover trabalho entre dois espaços de trabalho que administra. Um projeto pessoal precisa ser seu nos dois lados.

| Status | Código | Significado |
| --- | --- | --- |
| 400 | `validation_error` | O workflow já está nesse projeto. |
| 403 | `not_permitted` | Você não pode mover esse workflow, ou não pode movê-lo para esse destino. |
| 404 | `not_found` | O workflow não existe, ou o projeto não existe para você. |
| 409 | `move_blocked` | O trabalho foi criado para uma atividade. |
| 409 | `workspace_archived` | O espaço de trabalho de destino está arquivado. |

Uma movimentação que muda de espaço de trabalho remove as concessões de acesso dos colaboradores do workflow e as informa, para que você possa avisar as pessoas que perderam o acesso:

```json
{
"data": { "id": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f", "projectId": "5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716" },
"droppedCollaborators": [{ "userId": "2b3c4d5e-6f70-4a81-92b3-c4d5e6f70812", "name": "Sam" }]
}
```

A forma com `PATCH` só inclui `droppedCollaborators` quando alguma concessão foi removida.

## Escopos OAuth para workflows
| Escopo | Rotas |
| --- | --- |
| `workflows:read` | `GET /v1/projects/:projectId/workflows`, `GET /v1/workflows`, `GET /v1/workflows/:id`, `GET /v1/workflows/:id/export` |
| `workflows:write` | Criar, atualizar, excluir, importar e mover, além de `POST /v1/workflows/:parentId/sub-workflows` |
| `workflows:execute` | `POST /v1/workflows/:id/run` |

Tokens de API pessoais não precisam de escopos. Veja [Apps OAuth](https://nodaro.ai/docs/developers/oauth).

## Nós de produções do Studio
Alguns nós do canvas pertencem a uma produção do Studio e dependem de quadros vinculados. Eles precisam ser gerados pela API de produções do Studio: executá-los por `POST /v1/workflows/:id/run`, ou gerar um deles diretamente, responde `400 sequence_execution_required`. Veja [Produções do Studio](https://nodaro.ai/docs/developers/api/studio-productions).

## Frequently asked questions

### Como executo um workflow do Nodaro pela API?

Envie POST /v1/workflows/:id/run. Essa rota executa o workflow salvo e responde 202 com um executionId, que você consulta periodicamente. Para mudar os valores de entrada de uma única execução, use POST /v1/api/run com um objeto inputs e um token de API pessoal.

### Como passo valores de entrada para a execução de um workflow?

Envie um objeto inputs para POST /v1/api/run, com chaves pelo id do nó ou por um rótulo único de nó, e o campo do nó dentro de cada chave, por exemplo text. GET /v1/api/schema lista os campos de entrada de um workflow.

### Posso aguardar o resultado de um workflow em uma única requisição?

Sim. Adicione ?wait=true&timeout=120 a POST /v1/api/run. O servidor mantém a conexão aberta por até 600 segundos e retorna as saídas. Se a execução ainda estiver em andamento, ele responde 202 com o executionId, e você passa a consultar periodicamente a partir daí.

### Por que a API mudou a proporção ou a resolução que eu enviei?

O modelo que você escolheu não aceita esse valor. Em vez de fazer a execução falhar, o Nodaro corrigiu o valor para o mais próximo que o modelo aceita. A resposta lista cada alteração em adjustments, e os créditos são cobrados pelo valor corrigido.

### Uma execução pela API pode mudar para onde um workflow envia os resultados?

Não. Os campos de destino dos nós externos, como a URL de um nó Saída de webhook ou a conta de um nó de publicação em redes sociais, não podem ser substituídos por uma execução. Uma requisição que tenta fazer isso recebe 400 locked_field.
