# Espaços de trabalho e organizações

> Atue no espaço de trabalho de uma organização pela API do Nodaro (X-Nodaro-Workspace), vincule tokens e gerencie membros, convites, compartilhamento e uso.

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

Os **espaços de trabalho** são onde os membros de uma organização trabalham juntos: uma turma em uma escola, uma equipe em uma empresa. Uma requisição de API atua em um espaço de trabalho quando você envia o id dele no cabeçalho `X-Nodaro-Workspace`. Os endpoints de organização gerenciam tudo em volta: organizações, membros, convites, códigos de entrada, compartilhamento, orçamentos e uso.

As organizações são um recurso do Nodaro Cloud e são ativadas por instância. Onde não estão ativadas, os endpoints abaixo não existem e o cabeçalho é ignorado. As versões self-hosted não incluem organizações. Leia [Espaços de trabalho](https://nodaro.ai/docs/concepts/workspaces) para entender os conceitos.

## Atuar em um espaço de trabalho
```http
X-Nodaro-Workspace: 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34
```

O cabeçalho faz duas coisas, e só essas duas: decide **qual espaço de trabalho uma listagem retorna** e **onde fica o que você cria**. Ele nunca concede acesso. Ler, atualizar, excluir ou executar algo que você indica pelo id segue o espaço de trabalho do próprio objeto. Um cabeçalho esquecido não pode esconder seu trabalho, e um cabeçalho forjado não pode acessar o trabalho de mais ninguém.

Sem o cabeçalho, você trabalha no seu espaço pessoal, como sempre acontece com uma conta sem organização.

**curl**

```bash
curl -s https://app.nodaro.ai/v1/workflows \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "X-Nodaro-Workspace: 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34"
```

**TypeScript SDK**

```ts
// Every request of this client acts in the workspace:
const classClient = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
workspaceId: '6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34',
})

// Or derive a second client from an existing one:
const classroom = client.withWorkspace(workspaceId)
await classroom.workflows.run(workflowId) // lands in the class
await client.workflows.run(workflowId)    // lands in the personal space
```

**CLI**

```bash
nodaro --workspace 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34 workflows list   # this command only
export NODARO_WORKSPACE=6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34            # this shell or CI job
nodaro workspace use 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34                # saved on the profile
nodaro workspace current                                                # which one applies, and why
```

`client.withWorkspace` retorna um cliente **novo** em vez de alterar o antigo, então duas operações executadas ao mesmo tempo nunca disputam o espaço de trabalho em que estão. Passe `null` para o espaço pessoal. Na CLI, cada uma das três formas tem prioridade sobre a que vem abaixo dela, e `nodaro workspace use` verifica o espaço de trabalho antes de salvá-lo.

Envie o cabeçalho apenas para um espaço de trabalho do qual você faz parte:

| Status | Código | Quando |
| --- | --- | --- |
| 400 | `validation_error` | O valor não é um UUID. |
| 403 | `not_a_member` | Você não é membro desse espaço de trabalho, ele não existe, ou a organização dele não está ativa. |
| 403 | `member_suspended` | Sua participação está suspensa. |

Estas requisições nunca recusam uma seleção desatualizada, para que ela nunca bloqueie o seu acesso: `GET /v1/me`, `GET /v1/workspaces`, a leitura e a aceitação de um convite e a entrada em um espaço de trabalho com um código. Nelas, um espaço de trabalho que você não pode mais selecionar é tratado como se você não tivesse enviado nenhum cabeçalho. `GET /v1/me` e `GET /v1/workspaces` informam quais espaços de trabalho você pode selecionar, então limpe uma seleção guardada em cache quando eles deixarem de listá-la.

## Vincular um token a um espaço de trabalho
Um token de API pode ser vinculado a um espaço de trabalho. Ele passa a agir como se enviasse o cabeçalho em todas as requisições, e um cabeçalho explícito que indique outro espaço de trabalho responde `400 token_workspace_mismatch`.

```bash
# Bind
curl -X PATCH https://app.nodaro.ai/v1/api-tokens/$TOKEN_ID \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{"workspaceId": "6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34"}'

# Unbind
curl -X PATCH https://app.nodaro.ai/v1/api-tokens/$TOKEN_ID \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{"workspaceId": null}'
```

O gerenciamento de tokens exige o JWT da sua sessão de login: um token de API ou um token OAuth recebe `403 forbidden`. Você só pode vincular um token a um espaço de trabalho que poderia selecionar com o cabeçalho, e desvincular é sempre permitido. A listagem dos seus tokens retorna o vínculo como `workspaceId`.

## Onde fica o que você cria
- **Dentro de um espaço de trabalho, o que você cria fica no espaço de trabalho**, nunca no seu espaço pessoal. Uma criação que não indica um projeto vai para o projeto do espaço de trabalho. Quando o espaço de trabalho ainda não tem projeto, a criação responde `409 workspace_has_no_default_project`: indique um projeto, e ela funciona.
- **Um projeto que você indica precisa pertencer ao espaço de trabalho em que você atua.** Um projeto de outro espaço de trabalho, ou do seu espaço pessoal, responde `404 Project not found`. É a mesma resposta de um projeto que não existe, então o cabeçalho não pode ser usado para descobrir o que existe.
- **A criação de projetos pode ser limitada aos administradores.** Nesse caso, os membros recebem `403 project_create_not_allowed`.
- **Uma organização pode desativar o espaço pessoal.** Nesse caso, os membros só criam dentro de um espaço de trabalho, e uma criação sem o cabeçalho responde `403 personal_space_disabled`. Contas sem organização nunca são afetadas.

## Espaços de trabalho arquivados são somente leitura
Arquivar um espaço de trabalho mantém tudo o que há nele disponível para leitura e impede que novos trabalhos sejam adicionados. As listagens se comportam como antes. Toda criação, seja de um projeto, de um workflow, de uma importação ou de um sub-workflow, responde `409 workspace_archived`, e o mesmo vale para mover trabalho para dentro do espaço de trabalho. Mover trabalho para fora continua permitido, porque resgatá-lo é o motivo para abrir um espaço de trabalho arquivado. Outras gravações nele, como compartilhar um workflow, respondem `403 workspace_archived`. Compare pelo código, não pelo status.

## Quem é você: GET /v1/me
`GET /v1/me` retorna o seu perfil. Em uma instância com organizações, ele também traz `organizations`, `workspaces` e `lastWorkspaceId`, e cada entrada vem com a sua própria função e o seu status. As entradas de organização incluem o `vocabulary` resolvido, como a palavra que a organização usa para um espaço de trabalho, para que um cliente nunca fixe no código “Class” ou “Team”. `GET /v1/workspaces` retorna sozinho a mesma lista de espaços de trabalho.

Diferencie os três estados dos campos de organização:

| O que você vê | O que significa | O que fazer |
| --- | --- | --- |
| Os campos não aparecem | Esta instância não tem organizações. | Nunca mostre um seletor de espaço de trabalho. |
| Presentes e vazios | A conta não pertence a nenhuma organização. | Ofereça criar uma organização ou entrar em uma. |
| `organizationsUnavailable: true` | A consulta falhou. | Mantenha a seleção que você tinha. |

## Endpoints de organização
Todos os endpoints exigem autenticação. Os corpos são JSON, as respostas são `{ "data": … }`, as listas são `{ "data": [ … ], "nextCursor": … }`, e os ids são UUIDs.

### Organizações
| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `POST` | `/v1/orgs` | Qualquer pessoa conectada | `{ name, kind, slug?, acceptTerms?, settings? }`, em que `kind` é `school` ou `team`. Retorna `201`. |
| `GET` | `/v1/orgs` | Qualquer pessoa | Suas organizações, com o seu `role` e o seu `memberStatus`. |
| `GET` | `/v1/orgs/:id` | Membro | |
| `PATCH` | `/v1/orgs/:id` | Proprietário, administrador | `{ name?, settings? }`. As configurações são mescladas chave por chave, e as chaves desconhecidas são descartadas. |
| `POST` | `/v1/orgs/:id/transfer-ownership` | Proprietário | `{ userId }`. O novo proprietário precisa ser um administrador ativo, e o antigo proprietário passa a ser administrador na mesma operação. |
| `DELETE` | `/v1/orgs/:id` | Proprietário | Recusado com `409 has_active_workspaces` enquanto houver algum espaço de trabalho não arquivado. A organização é excluída de forma lógica (soft delete), e o slug dela é liberado. |
| `POST` | `/v1/orgs/:id/leave` | Membro | O proprietário não pode sair (`409 owner_cannot_leave`): transfira a propriedade antes. Sair remove você de todos os espaços de trabalho da organização. |

- **Aprovação.** Uma nova organização normalmente começa como `pending` e passa a `active` quando a plataforma a aprova. Enquanto ela aguarda, o proprietário a vê, mais ninguém a vê, e nada nela pode mudar. Avise quem a criou; caso contrário, a espera parece uma falha.
- **Escolas exigem os termos.** Criar uma escola exige `acceptTerms: true`, com o qual o proprietário confirma ter autoridade para matricular alunos. Sem isso, a criação responde `400 terms_required`.
- **Os slugs** têm de 1 a 50 letras minúsculas, dígitos e hifens. Um slug que você envia precisa estar livre (`409 name_taken`). Sem slug, ele é derivado do nome: “Sunrise School” vira `sunrise-school`, depois `sunrise-school-2`.
- A criação de organizações é limitada a algumas por hora para cada usuário.

### Membros
| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `GET` | `/v1/orgs/:id/members` | Proprietário, administrador | `?limit=50&cursor=…`, até 200. Linhas: `userId`, `role`, `status`, `joinedAt`, `email`, `displayName`, `avatarUrl`. |
| `PATCH` | `/v1/orgs/:id/members/:userId` | Proprietário, administrador | `{ role?, status? }`: `admin` ou `member`, `active` ou `suspended`. Não vale para a linha do proprietário. |
| `DELETE` | `/v1/orgs/:id/members/:userId` | Proprietário, administrador | Não vale para o proprietário. Também remove a pessoa de todos os espaços de trabalho da organização. |

### Espaços de trabalho
| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `POST` | `/v1/orgs/:id/workspaces` | Proprietário, administrador | `{ name, slug?, description?, settings? }`. Retorna `201`. Os slugs são únicos dentro da organização. |
| `GET` | `/v1/orgs/:id/workspaces` | Membro | Os membros veem os próprios espaços de trabalho; proprietários e administradores veem todos. `?includeArchived=true` inclui os arquivados. |
| `GET` | `/v1/workspaces` | Qualquer pessoa | Todos os espaços de trabalho de que você faz parte, em todas as organizações. |
| `GET` | `/v1/workspaces/:id` | Membro do espaço de trabalho | |
| `PATCH` | `/v1/workspaces/:id` | Administrador do espaço de trabalho | `{ name?, description?, settings? }` |
| `POST` | `/v1/workspaces/:id/archive` | Proprietário, administrador | Arquiva. É reversível, e nada é destruído. |
| `POST` | `/v1/workspaces/:id/unarchive` | Proprietário, administrador | Desarquiva. |

### Membros do espaço de trabalho
| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `GET` | `/v1/workspaces/:id/members` | Membro do espaço de trabalho | `?limit&cursor`. Os membros veem `userId`, `role`, `displayName`, `avatarUrl` e `addedAt`. Os administradores também veem `status` e `creditCap`. A lista de membros não tem endereços de e-mail. |
| `POST` | `/v1/workspaces/:id/members` | Administrador do espaço de trabalho | `{ userId, role }`, com `role` igual a `admin` ou `member`. A pessoa já precisa ser um membro ativo da organização (`400 not_org_member`): para trazer alguém novo, convide a pessoa. |
| `PATCH` | `/v1/workspaces/:id/members/:userId` | Administrador do espaço de trabalho | `{ role?, status?, creditCap? }`. `creditCap` é o limite de gastos do membro, ou `null` para nenhum limite. |
| `DELETE` | `/v1/workspaces/:id/members/:userId` | Administrador do espaço de trabalho | Remove a pessoa apenas do espaço de trabalho. Ela continua na organização. |

Os proprietários e os administradores da organização são administradores de todos os espaços de trabalho da organização sem aparecer na lista. Adicionar um deles explicitamente a um espaço de trabalho dá a essa pessoa a função explícita atribuída, no lugar da implícita. É assim que um administrador da organização pode ser um membro comum de uma turma.

### Convites
Um convite indica um único endereço de e-mail. O link dele leva um token que só existe no e-mail, e a pessoa convidada vê para o que foi convidada antes de fazer login.

| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `POST` | `/v1/orgs/:id/invitations` | Proprietário, administrador e, quando a organização permite, administradores de espaço de trabalho para o próprio espaço de trabalho | `{ emails, orgRole?, workspaceId?, workspaceRole? }`. Até 200 endereços, convertidos para minúsculas e sem duplicatas. Retorna `201` com uma linha por endereço: `{ email, status, link? }`. |
| `GET` | `/v1/orgs/:id/invitations` | As mesmas pessoas | `?status=` (`open`, `accepted`, `revoked` ou `expired`), `workspaceId`, `limit` e `cursor`. Nunca retorna um token. |
| `DELETE` | `/v1/invitations/:id` | As mesmas pessoas | Revoga o convite. O link para de funcionar. Recusado para um convite já aceito. |
| `POST` | `/v1/invitations/:id/resend` | As mesmas pessoas | Emite um novo token e uma nova validade e envia o convite de novo. O link anterior para de funcionar. |
| `GET` | `/v1/invitations/by-token/:token` | Público | O que a pessoa convidada precisa para decidir: `orgName`, `kind`, `vocabulary`, `inviterName`, `workspaceName`, o endereço de e-mail mascarado, `expiresAt` e `state`. Limitado por endereço IP. |
| `POST` | `/v1/invitations/:token/accept` | A pessoa convidada, já conectada | O e-mail da conta precisa corresponder ao do convite (`400 email_mismatch`). Uma segunda aceitação é recusada. |

- **Cada endereço recebe sua própria linha.** `status` é `sent`, `link_only` ou `failed`, e `link` aparece sempre que o endereço não recebeu e-mail. Uma instalação sem provedor de e-mail retorna todos os endereços como `link_only`. Mostre esses links: o convite existe de qualquer forma, e sem o link ninguém consegue chegar até ele.
- **Os convites expiram depois de 14 dias**, e uma organização pode enviar 500 por dia (`429 bulk_invite_cap_exceeded`).
- **Convidar um endereço de novo** passa o convite em aberto para um token novo, em vez de criar um segundo convite.
- **Convidar alguém que já é membro** consome o convite, mas não muda a função da pessoa nem remove uma suspensão.

### Códigos de entrada
Um código de entrada tem oito caracteres, curto o bastante para ser lido em voz alta em uma sala. Ele admite um **membro** comum em um espaço de trabalho, nunca remove uma suspensão e respeita os domínios de e-mail permitidos pela organização.

| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `GET` | `/v1/workspaces/:id/join-code` | Administrador do espaço de trabalho | `{ code, enabled, rotatedAt, rotatedBy }`, ou `null` quando nenhum código foi criado. |
| `POST` | `/v1/workspaces/:id/join-code` | Administrador do espaço de trabalho | `{ action }`: `rotate`, `enable` ou `disable`. Ativar em um espaço de trabalho que nunca teve código cria um. A rotação substitui o código, e o antigo para de funcionar na hora. |
| `POST` | `/v1/workspaces/join` | Qualquer pessoa conectada | `{ code }`. As formas faladas funcionam: `BCDF-GHJK`, letras minúsculas e letras que costumam ser confundidas ao ouvir, como `O` no lugar de zero. Limitado a 10 tentativas por minuto por conta e a 30 por endereço IP. |

### Compartilhar um workflow
Uma concessão de acesso dá a uma pessoa acesso a um workflow. Ela só pode adicionar acesso, nunca removê-lo.

| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `GET` | `/v1/workflows/:id/collaborators` | Quem pode ver o workflow | Linhas de `{ userId, name, avatarUrl, role, createdAt }`, nunca um endereço de e-mail. |
| `POST` | `/v1/workflows/:id/collaborators` | Veja abaixo | `{ userId }` ou `{ email }`, exatamente um dos dois, mais `role`: `viewer` ou `editor`. Retorna `201`. Limitado a 20 adições por minuto. |
| `PATCH` | `/v1/workflows/:id/collaborators/:userId` | Os mesmos do `POST` | `{ role }` |
| `DELETE` | `/v1/workflows/:id/collaborators/:userId` | Os mesmos do `POST`, ou você mesmo | Qualquer pessoa pode remover o próprio acesso. |
| `GET` | `/v1/workflows/shared-with-me` | Qualquer pessoa conectada | Os workflows em que você tem uma concessão, fora dos seus próprios espaços de trabalho, cada um com o seu `grantedRole`. Os mais recentes primeiro, até 200. |
| `GET` | `/v1/workflows/:id/access` | Quem pode vê-lo | `{ access, workspaceId, visibility, canChangeVisibility, canShare, canRun }`, nunca o grafo. |

- **Quem pode compartilhar:** o criador; um administrador do espaço de trabalho, onde os administradores podem editar o trabalho dos membros; e qualquer pessoa que possa editar o workflow, onde o espaço de trabalho permite que colaboradores convidem.
- **Adicionar por e-mail** encontra o endereço de qualquer conta, seja qual for a organização dela. `404` significa que não existe conta, e nada além disso é revelado.
- **Alguém de fora do espaço de trabalho fica limitado a visualizar**, mesmo com uma concessão de editor. Executar exige ser membro ativo, então um colaborador de fora nunca pode gastar os créditos do espaço de trabalho.
- Você não pode dar uma concessão ao criador do workflow nem a si mesmo (`400`). Uma concessão vale na hora, sem etapa de aceitação.
- `canChangeVisibility`, `canShare` e `canRun` são três regras separadas. Nunca deduza uma a partir de outra.

Um workflow que você não consegue acessar de forma alguma responde `404`, igual a um que não existe. Só quando você já consegue vê-lo e precisa de mais acesso é que a resposta passa a ser `403`. Executar um workflow que pertence a um espaço de trabalho exige acesso de edição e ser membro ativo.

### Log de auditoria
| Método | Caminho | Quem | Corpo ou query |
| --- | --- | --- | --- |
| `GET` | `/v1/orgs/:id/audit` | Proprietário, administrador | `?cursor&limit`, os mais recentes primeiro. Cada entrada: `{ id, workspaceId, action, targetType, targetId, details, createdAt, actor }`. `actor` é `null` para ações feitas pelo sistema. |

O log de auditoria continua disponível para leitura enquanto a organização está suspensa. `action` é uma lista aberta que cresce com o produto: mostre as ações que você conhece e, para as demais, use o valor bruto.

## Funções e configurações
| Escopo | Função | Pode |
| --- | --- | --- |
| Organização | `owner` | Tudo o que um administrador pode, além de transferir a propriedade e excluir a organização. Existe exatamente um. O proprietário não pode ser suspenso, removido nem rebaixado. |
| Organização | `admin` | Gerenciar as configurações, os membros além do proprietário e os espaços de trabalho. É administrador de todos os espaços de trabalho. |
| Organização | `member` | Pertencer à organização e trabalhar nos espaços de trabalho aos quais for adicionado. |
| Espaço de trabalho | `admin` | Gerenciar as configurações e os membros do espaço de trabalho. |
| Espaço de trabalho | `member` | Trabalhar no espaço de trabalho. |

As configurações funcionam em camadas: a configuração de um espaço de trabalho prevalece sobre a da organização, que prevalece sobre o padrão do tipo de organização. Uma chave não definida passa para a camada seguinte, e `false` é um valor real.

| Chave | Valores | Controla |
| --- | --- | --- |
| `admin_access` | `view` ou `edit` | O que os administradores podem fazer com o workflow de um membro. |
| `default_workflow_visibility` | `private` ou `workspace` | A visibilidade de um novo workflow. |
| `member_access_to_shared` | `view` ou `edit` | O que os membros podem fazer com um workflow compartilhado com o espaço de trabalho. |
| `members_can_create_projects` | booleano | Se os membros podem criar projetos. |
| `member_caps_enabled` | booleano | Se os limites de créditos por membro se aplicam. |
| `personal_space_enabled` | booleano | Se os membros mantêm um espaço pessoal. |
| `workspace_admins_can_invite` | booleano | Se os administradores de espaço de trabalho podem convidar novas pessoas para a organização. |
| `collaborators_can_invite` | booleano | Se um colaborador editor pode convidar mais colaboradores. |

Só a organização tem também `allowed_email_domains`, como `["school.example"]`, e `vocabulary_overrides`, como `{ "workspace": "Cohort" }`. As duas chaves são substituídas por inteiro quando atualizadas.

Quando você define a sua própria palavra para um espaço de trabalho, defina também `workspace_gender` em `vocabulary_overrides` como `"m"` se a palavra for gramaticalmente masculina, por exemplo `{ "workspace": "Grupo", "workspace_gender": "m" }`. Assim, as frases em hebraico e em português do Brasil que citam o espaço de trabalho concordam com a palavra. Sem `"m"`, elas tratam a palavra como feminina. Essa configuração só existe na API.

Uma **escola** começa assim: administradores editam, workflows privados, membros veem o trabalho compartilhado, membros não podem criar projetos, limites ativados, espaço pessoal ativado, administradores de espaço de trabalho podem convidar e colaboradores não podem. Uma **equipe** começa assim: administradores veem, workflows visíveis para o espaço de trabalho, membros editam o trabalho compartilhado, membros podem criar projetos, limites desativados, espaço pessoal ativado e as duas configurações de convite ativadas.

## Orçamentos e uso
Uma organização paga pelo trabalho dos membros em três etapas, cada uma mais restrita que a anterior:

1. **O fundo comum.** A organização compra pacotes de créditos pré-pagos para um único fundo comum de toda a organização, pelo próprio checkout.
2. **Alocações.** O proprietário transfere créditos do fundo comum para o orçamento de um espaço de trabalho. O fundo comum diminui exatamente o que o espaço de trabalho ganha. Os créditos podem voltar para o fundo comum, mas a alocação do espaço de trabalho não pode ficar abaixo do que ele já reservou ou gastou.
3. **Limites por membro.** Dentro de um espaço de trabalho, um administrador pode limitar quanto um membro pode gastar. Os limites só se aplicam onde as configurações do espaço de trabalho os ativam, e nunca a um administrador da organização que trabalhe no espaço de trabalho.

O trabalho feito dentro de um espaço de trabalho é pago pelo espaço de trabalho, e os créditos do próprio membro não são usados. Em cada nível, a margem disponível é o valor alocado menos o reservado menos o gasto. Uma execução que ultrapassaria essa margem é recusada com `402 budget_exceeded` ou `402 member_cap_exceeded` antes de começar.

| Rota | Quem | O que faz |
| --- | --- | --- |
| `GET /v1/orgs/:id/credits` | Proprietário, administrador da organização | O fundo comum, o total de compras desde o início e a alocação de cada espaço de trabalho, com os créditos reservados e gastos. |
| `POST /v1/orgs/:id/credits/checkout` | Proprietário | Uma URL de checkout para um pacote pré-pago. Corpo: `{ packId }`. |
| `POST /v1/orgs/:id/workspaces/:wsId/allocate` | Proprietário | Transfere créditos entre o fundo comum e um espaço de trabalho. Corpo: `{ delta }`. Retorna a nova margem disponível. |
| `GET /v1/workspaces/:id/budget` | Membro | Seu gasto, seu limite e sua margem disponível. Os administradores também recebem uma linha para cada membro. |
| `GET /v1/orgs/:id/usage` | Proprietário, administrador da organização | Um relatório de uso da organização. |
| `GET /v1/workspaces/:id/usage` | Membro, administrador do espaço de trabalho | O mesmo, para um espaço de trabalho. |

Reembolsos e contestações de pagamento retiram créditos do fundo comum da organização na proporção correspondente, nunca abaixo de zero. Para excluir uma organização, é preciso recolher antes todas as alocações dos espaços de trabalho.

**As automações gastam os créditos do espaço de trabalho.** A URL de um nó [**Gatilho de webhook** (Webhook Trigger)](https://nodaro.ai/docs/nodes/automate/webhook-trigger) é uma credencial do tipo bearer: quem a tiver pode iniciar uma execução. A execução de um workflow de um espaço de trabalho é paga por esse espaço de trabalho. Toda execução automática, vinda de um webhook, de um agendamento ou do Telegram, verifica primeiro se quem criou o gatilho ainda pode executar o workflow. Quando essa pessoa não pode mais, a automação para, e o histórico de execuções mostra uma entrada com falha e o código `run_requires_authenticated_member`.

### Relatórios de uso
As duas rotas de uso respondem quem gastou quanto e em quê, em um intervalo de datas:

| Query | Significado |
| --- | --- |
| `from`, `to` | Datas inclusivas, `YYYY-MM-DD`. O intervalo tem no máximo 366 dias, e o padrão são os últimos 30. |
| `tz` | Um fuso horário IANA para os agrupamentos por dia. O padrão é `UTC`. |
| `groupBy` | `workspace` (só na organização), `member`, `model`, `day`, ou `none` para as execuções individuais, das mais recentes para as mais antigas, paginadas com `cursor`. |
| `workspaceId`, `userId` | Restringem o relatório. |
| `format` | `csv` retorna o relatório em CSV. |

- Cada linha tem três valores de créditos. `credits` é o que as execuções custaram até agora: o valor liquidado das execuções terminadas e a reserva retida das execuções em andamento. `settledCredits` e `inFlightCredits` dividem essa soma.
- Uma execução cobrada por consumo que custou mais do que o espaço de trabalho ainda tinha é cobrada até a margem disponível, e a plataforma absorve o restante. Os totais informam isso como `platformAbsorbedCredits`, e `settledCredits` menos `platformAbsorbedCredits` é o que chegou ao orçamento. Um acréscimo (markup) de app aprovado que o orçamento não conseguiu cobrir também é absorvido e informado à parte como `appMarkupAbsorbedCredits`.
- Um relatório com mais de 5.000 grupos retorna `truncated: true`. Só as linhas agrupadas são cortadas: os totais cobrem o intervalo inteiro.
- Um membro comum vê só as próprias execuções, e o agrupamento por membro é recusado para ele. Um administrador do espaço de trabalho vê todo mundo e pode filtrar por `userId`. O relatório da organização é para os proprietários e os administradores da organização.
- As exportações CSV são UTF-8, RFC 4180, com finais de linha CRLF e sem marca de ordem de bytes (BOM). Uma célula que começa com `=`, `+`, `-` ou `@` recebe um apóstrofo no início, para que uma planilha não possa executá-la. As exportações são limitadas a 10 por minuto para cada usuário e ficam registradas no log de auditoria.
- Quando um membro exclui a própria conta, o histórico de execuções dele vai junto, e o relatório mostra uma lacuna. Os workflows e os projetos dele ficam com o espaço de trabalho.

Uma instância sem relatórios de uso responde `404`, e responde `503 billing_unavailable` enquanto os relatórios ainda não estão disponíveis.

## Erros
| Status | Código | Quando |
| --- | --- | --- |
| 400 | `validation_error` | Um campo é inválido, um cursor está malformado, a alteração não é permitida para aquela linha, ou um relatório de uso tem uma data, um fuso horário, um intervalo ou um agrupamento inválidos. |
| 400 | `terms_required` | Criação de uma escola sem `acceptTerms: true`. |
| 400 | `not_org_member` | Adição a um espaço de trabalho de alguém que não é membro ativo da organização dele. |
| 400 | `token_workspace_mismatch` | Um token vinculado a um espaço de trabalho, com um cabeçalho que indica outro. |
| 400 | `join_code_invalid` | O código não existe, está desativado, ou o espaço de trabalho dele está arquivado. Uma única resposta para os três casos. |
| 400 | `invitation_expired`, `invitation_revoked`, `invitation_accepted` | O convite passou dos 14 dias, foi revogado ou já foi aceito. |
| 400 | `email_mismatch` | O e-mail da conta conectada não é o e-mail convidado. |
| 401 | `unauthorized` | Não há credenciais válidas. |
| 403 | `insufficient_role` | Você é membro, mas a sua função não permite a ação. |
| 403 | `member_suspended` | Sua participação está suspensa. |
| 403 | `org_not_active` | A organização está pendente ou suspensa, e a ação altera algo. |
| 403 | `workspace_archived` | Uma gravação em um espaço de trabalho arquivado. |
| 403 | `not_a_member` | O cabeçalho indica um espaço de trabalho que você não pode selecionar. |
| 403 | `domain_not_allowed` | A organização só aceita os domínios de e-mail listados. |
| 404 | `not_found` | A organização, o espaço de trabalho ou o membro não existe, ou você não é membro da organização ou do espaço de trabalho. |
| 404 | `invitation_not_found` | Não há convite para esse token, incluindo um convite cuja organização não está ativa. |
| 409 | `name_taken` | O slug que você enviou já está em uso. |
| 409 | `already_a_member` | A pessoa já está no espaço de trabalho. |
| 409 | `owner_cannot_leave` | Transfira a propriedade antes de sair. |
| 409 | `has_active_workspaces` | Arquive todos os espaços de trabalho antes de excluir a organização. |
| 429 | `rate_limit_exceeded` | Organizações criadas, tentativas de entrada ou exportações CSV em excesso. |
| 429 | `bulk_invite_cap_exceeded` | A organização atingiu o limite diário de convites. |
| 503 | `billing_unavailable` | Os relatórios de uso ainda não estão disponíveis nesta instância. |
| 503 | `audit_unavailable` | Uma exportação CSV não pôde ser registrada no log de auditoria, por isso foi recusada. Tente novamente. |

## Pelo SDK, pela CLI e pelo MCP
- **SDK:** `client.organizations` e `client.workspaces` cobrem esses endpoints, incluindo `usage`, `usageRows` e `usageCsv` para os relatórios. `client.me()` traz os campos de organização.
- **CLI:** `nodaro org` e `nodaro workspace`, por exemplo `nodaro org invite <orgId> --email ada@school.example --workspace <id>` e `nodaro org usage <orgId> --from 2026-09-01 --to 2026-09-30 --group-by member --csv > september.csv`. O comando de convite imprime uma linha por endereço, com o link de cada endereço que não recebeu e-mail.
- **MCP:** as ferramentas `list_workspaces` e `select_workspace`. A seleção é lembrada entre as sessões e verificada de novo em cada uma. Um app OAuth que usa essas ferramentas precisa dos escopos `workspaces:read` e `workspaces:write`.

Leia [A CLI](https://nodaro.ai/docs/developers/cli) e [O SDK](https://nodaro.ai/docs/developers/sdk) para ver as listas completas de comandos e de métodos.

## Frequently asked questions

### Como faço uma requisição à API do Nodaro atuar em um espaço de trabalho?

Envie o id do espaço de trabalho no cabeçalho X-Nodaro-Workspace. Ele decide qual espaço de trabalho uma listagem lê e onde fica o que você cria. No SDK, use createClient({ workspaceId }) ou client.withWorkspace(id); na CLI, use --workspace.

### Um cabeçalho de espaço de trabalho errado pode esconder meu trabalho ou acessar o de outra pessoa?

Não. O cabeçalho decide o escopo, nunca o acesso. Ler, alterar, excluir ou executar algo pelo id segue o espaço de trabalho do próprio objeto, e um espaço de trabalho do qual você não faz parte responde 403 not_a_member.

### Posso vincular um token de API a um único espaço de trabalho?

Sim. Vincule o token com PATCH /v1/api-tokens/:id e um workspaceId, a partir de uma sessão de login. O token passa a agir como se enviasse o cabeçalho em todas as requisições, e um cabeçalho que indique outro espaço de trabalho responde 400 token_workspace_mismatch.

### Por que uma criação responde 403 personal_space_disabled?

Sua organização exige que os membros criem trabalhos dentro de um espaço de trabalho. Envie o cabeçalho X-Nodaro-Workspace com um dos seus espaços de trabalho, e a mesma chamada funciona.

### As organizações estão disponíveis em instalações self-hosted?

Não. As organizações são um recurso do Nodaro Cloud, ativado por instância. As versões self-hosted não as incluem e ignoram o cabeçalho de espaço de trabalho.

### Por que um convite voltou com um link em vez de ser enviado por e-mail?

A instalação não tem um provedor de e-mail, ou o envio falhou. O convite existe de qualquer forma, então envie você mesmo o link retornado para a pessoa.
