Pular para o conteúdo

Autenticação e visão geral (referência)

API pública da Nebular para agents e automações: gerencie projetos, serviços, deploys, variáveis, domínios, volumes, bancos e templates e as galerias de arquivos servidas pela CDN (*.nebularcdn.com). Todas as rotas ficam em /v1, usam apenas Authorization: Bearer e respondem JSON (application/json; charset=utf-8, sempre Cache-Control: no-store). Esta especificação é servida em GET /v1/openapi.json (pública) e é validada contra o código a cada mudança.

No painel: Time → Configurações → Tokens de API. A criação exige papel admin do time e confirmação recente de identidade (step-up). O token tem o formato nbk_<…>, é exibido uma única vez (guardamos apenas o hash SHA-256), vale 90 dias por padrão (máximo 1 ano) e pode ser revogado a qualquer momento. Ele pertence ao time, nunca a uma pessoa. Pode ser restrito a algumas galerias (assets:*) e/ou a alguns projetos (project_ids).

O token vai somente no cabeçalho Authorization: Bearer nbk_…. Nunca o envie em query string. Cookies são ignorados nestas rotas (não há CSRF por construção) e as rotas de sessão do painel não aceitam Bearer. Cada operação indica os escopos exigidos na extensão x-required-scopes (todos são necessários) e, quando um escopo opcional muda a resposta, em x-optional-scopes.

Escopo Permite
assets:read listar galerias e arquivos, consultar detalhes e status de varredura
assets:write enviar, versionar e excluir arquivos
galleries:manage criar galerias
projects:read ler projetos, serviços, deployments, domínios, volumes, bancos e backups
projects:write criar, editar e apagar projetos e serviços
deploy disparar, cancelar e reverter deploys (serviço e grupo), enviar código-fonte
env:read ler variáveis (valores sensíveis vêm null)
env:write criar, alterar e apagar variáveis
env:reveal ler valores sensíveis, resolved=true e credenciais de banco. Exige env:read e que o token tenha sido criado com confirmação de identidade (step-up)
domains:write anexar e remover domínios
volumes:write anexar, aumentar e apagar o volume
databases:write criar, alterar, apagar, rotacionar, backup e restore de bancos
logs:read ler log de build e de execução
templates:deploy listar e instanciar templates

Token sem o escopo ⇒ 403 forbidden. Projeto de outro time, ou fora dos project_ids do token, é indistinguível de um projeto inexistente (404 not_found). GET /v1/me e GET /v1/limits aceitam qualquer token válido.

{p} nas rotas aceita o id (26 caracteres) ou o slug do projeto; {s} aceita o id ou o nome do serviço. Todo projeto nasce com um serviço web padrão. Variáveis podem referenciar outros serviços com ${{servico.VAR}} (ex.: ${{db.MYSQL_HOST}}); essas referências definem a ordem do deploy de grupo e são validadas no disparo.

POST …/deployments, POST …/deploy, rollback, backup e restore respondem 202 com um recurso em andamento. Acompanhe por polling com backoff (comece em 2 s e dobre até 15 s; não há webhooks neste ciclo):

  • deployment: queued → building → deploying → ready, ou failed, blocked, canceled, superseded; em failed, error traz code, message e details;
  • deploy de grupo: running → ready | failed | canceled, com o estado de cada serviço em items[].status;
  • job de banco: queued → running → done | failed;
  • domínio: pending_dns → verifying → active | error.

Todo POST que cria ou dispara aceita Idempotency-Key (8 a 128 caracteres [A-Za-z0-9._:-]). Mesma chave + mesmo pedido em 24 h devolve a mesma resposta (com Idempotent-Replay: true); mesma chave com pedido diferente ⇒ 422 idempotency_conflict; chave malformada ⇒ 400. Só respostas 2xx são gravadas, então repetir depois de uma falha executa de verdade. O upload de arquivos de galeria tem regra própria (409 idempotency_conflict, mais abaixo).

Listas devolvem {"items": […], "next_cursor": "…"|null, "has_more": bool}. Passe next_cursor em ?cursor= para a página seguinte e use ?limit= de 1 a 200 (padrão 50). O cursor é opaco; cursor malformado ⇒ 400 invalid_request. Deployments, backups e a lista de projetos vêm do mais novo para o mais antigo; as demais do mais antigo para o mais novo (variáveis por nome).

Variáveis marcadas sensitive nunca voltam em claro por padrão (value: null); a resposta de PUT nunca ecoa um valor sensível; logs saem com segredos mascarados. Credenciais de banco só saem em POST …/credentials (nunca GET), com env:reveal, e a leitura é auditada.

  • Plano do time: serviços, memória, volumes, bancos e deploys por hora (GET /v1/limits). Ao atingir ⇒ 422 quota_exceeded.
  • Corpo JSON até 16 KiB (variáveis até 96 KiB por variável e 1 MiB no lote; serviços e templates até 64 KiB); código-fonte (multipart) até 512 MB.
  • Galerias: 25 MB por arquivo (imagens também limitadas a 40 megapixels); cota por time no bucket compartilhado de 5 GB e 10 000 arquivos. Nomes de arquivo: até 4 segmentos separados por / (3 barras), cada um em [a-z0-9._-], até 200 caracteres, sem .., sem segmento iniciando com . e com o primeiro segmento diferente de 12 caracteres hexadecimais minúsculos; únicos dentro da galeria. Nome inválido ⇒ 400 invalid_request.
  • Rate-limit por token e por IP: ao receber 429, espere Retry-After segundos.

O tipo é detectado pelo conteúdo (magic bytes), nunca pela extensão ou pelo Content-Type enviado. Extensão divergente do conteúdo em executável/documento é recusada (415 extension_mismatch).

Classe Exemplos Servido como
image png, jpeg, webp, gif, avif inline, transformável (?w=, ?q=)
svg svg inline só se passar na varredura de SVG, com CSP restritiva
font woff2, woff, ttf, otf inline, CORS *
media mp4, webm, mp3, ogg inline, com Accept-Ranges
document pdf, txt, csv, json Content-Disposition: attachment; texto sempre text/plain
markup html, htm, xhtml, xml nunca renderiza: attachment + text/plain + CSP sandbox
archive zip, tar.gz, 7z attachment; arquivo cifrado ou impossível de varrer é recusado
binary exe, msi, dmg, apk, deb, appimage, desconhecido attachment, application/octet-stream

Todo upload entra em quarentena e passa por antivírus, regras YARA, reputação por hash (só o hash sai da nossa infra), varredura específica de SVG e decodificação segura de imagens. Detectado ⇒ 422 e a amostra não é guardada. Scanner indisponível ⇒ o arquivo fica pending e não é publicado (resposta 202; consulte o GET do arquivo até scan.status sair de pending). Todo dia os arquivos publicados são reescaneados com as assinaturas novas: uma detecção move o arquivo para quarantined (deixa de ser servido, responde 451, o cache é purgado e o time é avisado).

Todo erro tem o formato {"error": "<code>", "message": "…", "details"?: {…}}; message é legível (pt-BR) e error é estável para tratamento programático (enumerado em Error.error). Algumas respostas trazem details (ex.: references em unresolved_reference/reference_cycle: apenas nomes, nunca valores). Os 5xx e 429 trazem Retry-After quando repetir faz sentido. Nos corpos de serviço, variável e deploy, um campo desconhecido (ex.: memory_mb solto no topo; o certo é {"resources": {"memory_mb": 1024}}) é recusado com 400 invalid_request, e a mensagem nomeia o campo, em vez de ser ignorado em silêncio.

Status error
400 invalid_request, bad_json, bad_body
401 unauthorized (genérico de propósito: token ausente, inválido, expirado ou revogado)
403 forbidden
404 not_found
409 name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, gallery_not_empty, idempotency_conflict (upload de galeria)
413 too_large, payload_too_large
415 unsupported_media_type, unsupported_type, extension_mismatch, class_not_allowed
422 quota_exceeded, idempotency_conflict, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported
429 rate_limited
500 internal
503 unavailable, authz_unavailable, database_unavailable

O painel usa as mesmas operações em /api/teams/{tid}/… (sessão + CSRF, com confirmação de identidade em ações destrutivas). Essas rotas não fazem parte desta API pública e não aceitam Bearer.

  • https://api.nebularws.com — Produção
  • bearer: http (bearer) Token de API de time (nbk_…) criado em Time → Configurações → Tokens de API. Somente no cabeçalho Authorization: Bearer; nunca em query string. Cookies são ignorados nestas rotas.