Ambientes de Preview — API

Use estes endpoints para configurar e operar Ambientes de Preview aninhados em um projeto HTTP principal. Um preview tem identidade, URL, capacidade, storage e ciclo de cobrança próprios, mas só pode ser acessado pelo projeto principal ao qual pertence.

A operação é idempotente por organização, projeto principal e previewKey. PUT e DELETE podem retornar uma operação assíncrona; consulte o endpoint de operação até alcançar um estado terminal.

Autenticação e segurança

Inclua uma credencial com as permissões do projeto correspondente e, para automações, uma API Key da organização:

HeaderObrigatórioDescrição
x-api-keyNas operações de automaçãoAPI Key da organização, mantida em um secret.
x-organization-idCom token de usuárioOrganização ativa do projeto. A API Key da organização já está vinculada à organização.
Content-Type: application/jsonEm requests com bodyIndica um body JSON.

O owner precisa habilitar Ambientes de Preview no console antes que uma API Key da organização possa operar previews. A chave fica limitada ao projeto principal e aos guardrails configurados: ela não altera settings, entitlement, limites ou planos não permitidos.

Para o ciclo operacional mínimo, conceda no projeto principal project.read, project.preview.read, project.preview.deploy e project.preview.delete. project.preview.configure continua reservado à configuração inicial por usuário autorizado. Para custos, conceda também project.billing.read.

As respostas públicas nunca incluem variáveis de ambiente, credenciais, URLs privadas de imagem, nomes de recursos ou detalhes operacionais internos. Trate a API Key como segredo e não a registre.

URL base e identificadores

https://api.zenifra.com/v1

Nos exemplos, PROJECT_ID representa o ID do projeto HTTP principal e API_KEY representa uma API Key da organização mantida em um secret. Substitua apenas esses placeholders pelos valores da sua organização.

export PROJECT_ID="seu-project-id"
export API_KEY="sua-api-key"
export USER_TOKEN="seu-token-de-usuario"
export ORGANIZATION_ID="sua-organization-id"
export BASE_URL="https://api.zenifra.com/v1"

A previewKey deve usar somente letras, números, ponto, sublinhado e hífen, com 1 a 100 caracteres. Não altere silenciosamente uma chave rejeitada.

Endpoints

ObjetivoMétodo e rota
Consultar settingsGET /project/:projectId/preview-environments/settings
Atualizar settingsPATCH /project/:projectId/preview-environments/settings
Listar plano herdadoGET /project/:projectId/preview-environments/plans
Consultar custos dos previewsGET /project/:projectId/preview-environments/billing
Listar previewsGET /project/:projectId/preview-environments
Criar ou atualizar um previewPUT /project/:projectId/preview-environments/:previewKey
Consultar um previewGET /project/:projectId/preview-environments/:previewKey
Remover um previewDELETE /project/:projectId/preview-environments/:previewKey
Consultar uma operaçãoGET /project/:projectId/preview-environments/:previewKey/operations/:operationId

Settings do projeto

Consultar settings

GET /project/:projectId/preview-environments/settings

Retorna o opt-in e os guardrails efetivos do projeto principal. A resposta pública inclui enabled, o plano herdado do projeto em default_plan/allowed_plans, default_ttl_hours, max_ttl_hours, max_active_environments active_environments, organization_limits e a configuração dos previews nativos em github e forgejo. O Preview nunca pode escolher um plano diferente do projeto principal. Assim como a atualização, a consulta das settings exige sessão de usuário (API Key da organização não é aceita) e project.preview.read.

curl -sS "$BASE_URL/project/$PROJECT_ID/preview-environments/settings" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

Exemplo de resposta:

{
  "status": "success",
  "data": {
    "enabled": true,
    "default_plan": "basic",
    "allowed_plans": ["basic"],
    "default_ttl_hours": 24,
    "max_ttl_hours": 168,
    "max_active_environments": 2,
    "active_environments": 1,
    "github": {
      "enabled": true,
      "target_branch": "main"
    },
    "forgejo": {
      "enabled": false
    },
    "organization_limits": {
      "enabled": true,
      "max_active_environments": 10,
      "max_per_project": 2,
      "max_ttl_hours": 168,
      "active_environments": 3
    }
  }
}

Atualizar settings

PATCH /project/:projectId/preview-environments/settings

Requer sessão de usuário (API Key da organização não é aceita) e permissão de configuração no projeto. max_active_environments aceita de 0 a 1000. A API não permite alterar o entitlement da organização nem ultrapassar o limite efetivo.

{
  "enabled": true,
  "default_ttl_hours": 24,
  "max_ttl_hours": 168,
  "max_active_environments": 2,
  "github": {
    "enabled": true,
    "target_branch": "main"
  }
}

default_ttl_hours e max_ttl_hours devem estar entre 1 e 168, e o default não pode ser maior que o máximo. O preço horário sempre vem do plano do projeto principal.

Por padrão, github.enabled é false. Esse campo habilita o fluxo nativo para um projeto HTTP cuja origem seja um repositório GitHub. github.target_branch define a branch de destino dos pull requests que podem criar previews e é obrigatória quando github.enabled for true; quando o fluxo está desabilitado, ela pode ser omitida. A configuração de GitHub é independente de auto-deploy: ela não altera a branch ou a política de atualização da aplicação principal. Para projetos com origem Forgejo, o objeto forgejo aceita os mesmos campos (enabled e target_branch, obrigatória quando habilitado); veja Deploy a partir do Forgejo.

Quando o fluxo nativo está ativo, pull requests do próprio repositório com destino na branch escolhida usam a identidade pr-<number> nos eventos opened, reopened e synchronize. O evento edited reavalia uma mudança na branch de destino e closed remove o preview. Pull requests de forks não participam, e pull requests já abertos antes da ativação não são importados automaticamente; o próximo evento relevante inicia a avaliação.

O fluxo nativo usa o runtime e os comandos já configurados no projeto e não exige GitHub Action, API Key, IMAGE ou workflow no repositório. O endpoint PUT /project/:projectId/preview-environments/:previewKey continua sendo o caminho para a Action e outras automações que publicam uma imagem pronta.

Desabilitar github.enabled ou o opt-in global, alterar github.target_branch ou desconectar/trocar o repositório remove os previews nativos afetados e invalida publicações pendentes. A aplicação principal e sua configuração de auto-deploy permanecem separadas desse cleanup.

Custos dos previews

GET /project/:projectId/preview-environments/billing

Requer project.billing.read. Retorna o custo acumulado dos Previews ativos, a taxa horária atual e uma estimativa até a expiração de cada ambiente e do conjunto.

Os valores monetários são retornados em centavos de BRL, seguindo o contrato de billing existente. Por exemplo, 5.4 representa R$ 0,054. accrued_amount considera snapshots horários calculados até as_of; pending_amount identifica o valor ainda aguardando consolidação. estimated_until_expiration é uma estimativa, não uma cobrança final, e não inclui a hora corrente enquanto ela não tiver sido consolidada.

{
  "status": "success",
  "data": {
    "currency": "brl",
    "as_of": "2026-08-25T22:00:00.000Z",
    "previews": [
      {
        "preview_id": "preview-id",
        "key": "pr-42",
        "status": "running",
        "plan": "basic",
        "hourly_rate": 5.4,
        "accrued_amount": 10.8,
        "settled_amount": 5.4,
        "pending_amount": 5.4,
        "estimated_until_expiration": 21.6,
        "expires_at": "2026-08-26T02:00:00.000Z",
        "billing_status": "pending"
      }
    ],
    "summary": {
      "active_previews": 1,
      "accrued_amount": 10.8,
      "settled_amount": 5.4,
      "pending_amount": 5.4,
      "hourly_rate": 5.4,
      "estimated_until_expiration": 21.6
    }
  }
}

Planos

Listar planos de preview

GET /project/:projectId/preview-environments/plans

Retorna o plano do projeto principal e seus preços publicados em BRL. O endpoint existe para que o Console mostre o custo correto; não há um catálogo de planos exclusivo para Preview.

curl -sS "$BASE_URL/project/$PROJECT_ID/preview-environments/plans" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

O preço retornado pelo catálogo é a fonte de verdade. Não copie valores comerciais para a Action ou para a aplicação cliente.

Listar previews

GET /project/:projectId/preview-environments

Lista os previews aninhados no projeto principal. A resposta traz data.items e data.pagination.

curl -sS "$BASE_URL/project/$PROJECT_ID/preview-environments" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

Cada item pode conter os seguintes campos públicos:

CampoDescrição
idIdentificador público do preview.
keyChave estável que identifica o ambiente no projeto.
statusEstado de produto, como accepted, provisioning, available, deleting, deleted ou failed.
urlURL pública quando disponível.
planPlano selecionado.
payment_modeO preview usa cobrança hourly.
exposureExposição configurada para o ambiente.
inherit_envsSempre true: os ENVs do projeto principal são herdados. Nunca contém os valores.
updated_at e expires_atAtualização mais recente e expiração atual.

A lista não retorna ENVs, dados, credenciais, hashes, leases, contadores ou nomes de recursos.

Execuções nativas do GitHub

A resposta de GET /project/:projectId/preview-environments também traz data.github_runs e data.forgejo_runs, com as execuções nativas de pull requests de cada provedor (listas vazias quando não há execuções). Essas seções não alteram o formato dos itens de Preview e têm o mesmo formato entre si. A leitura usa a mesma permissão project.preview.read do projeto principal.

{
  "data": {
    "items": [],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 0
    },
    "github_runs": {
      "items": [
        {
          "preview_key": "pr-42",
          "pull_request_number": 42,
          "status": "building",
          "commit_sha": "abc123...",
          "branch": "feature/example",
          "target_branch": "main",
          "repository": "example-org/example-repository",
          "updated_at": "2026-09-16T18:30:00.000Z"
        }
      ],
      "pagination": {
        "page": 1,
        "limit": 20,
        "total": 1
      }
    }
  }
}

Os estados públicos de uma execução são queued, building, updating, available, failed, blocked, removing e removed. error pode aparecer somente quando houver uma falha e contém um erro de produto normalizado com code e message.

Enquanto a execução estiver pendente ou falhar, ela não representa um Preview disponível: ainda não há URL, aplicação em execução ou valores de cobrança do ambiente. Quando a execução chegar a available, consulte a lista ou o detalhe do Preview para obter os dados públicos do ambiente. Uma execução removing representa o encerramento do Preview associado, e removed mantém o registro histórico depois que o ambiente deixa de existir.

Se uma tentativa falhar, consulte error e envie um novo commit ou produza outro evento relevante do pull request para iniciar uma nova tentativa. A plataforma não promete repetir automaticamente uma tentativa cujo resultado não pôde ser confirmado.

Criar ou atualizar um preview

PUT /project/:projectId/preview-environments/:previewKey

Cria ou atualiza o preview identificado por previewKey. O corpo de um upsert aceita:

CampoTipoObrigatórioDescrição
imagestringSim no upsertReferência da imagem pronta a publicar (até 2.048 caracteres).
inherit_envsbooleanNãoCampo de compatibilidade legada; o Preview sempre herda os ENVs do usuário dentro da Zenifra.
ttl_hoursintegerNãoDuração em horas; default 24, mínimo 1, máximo 168.
sourceobjectNãoMetadados da origem enviados pela Action oficial: provider: "github_action" e, opcionalmente, event, repository, pull_request_number, branch, base_branch e commit_sha.

O preview usa sempre o plano do projeto principal e sincroniza sua porta, exposição e regras de acesso. O storage é novo e começa vazio para o preview. Dados, domínios personalizados e comandos customizados de imagem não são herdados.

curl -sS -X PUT \
  "$BASE_URL/project/$PROJECT_ID/preview-environments/pr-42" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "docker.io/library/nginx@sha256:6784fb0834aa7dbbe12e3d7471e69c290df3e6ba810dc38b34ae33d3c1c05f7d",

    "ttl_hours": 24
  }'

A API responde 202 com { "status": "accepted", "data": { "operation": {...}, "preview": {...} } }; operation.operation_id identifica a operação a consultar. Se houver uma operação ativa com payload incompatível, a API retorna 409 (PREVIEW_OPERATION_CONFLICT) e a operação existente deve ser consultada.

Consultar um preview

GET /project/:projectId/preview-environments/:previewKey

Exige project.preview.deploy. Retorna o estado atual, URL, plano, preço horário em BRL quando disponível, herança de ENVs, timestamps e a operação corrente. Não retorna valores de variáveis de ambiente.

curl -sS \
  "$BASE_URL/project/$PROJECT_ID/preview-environments/pr-42" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

Remover um preview

DELETE /project/:projectId/preview-environments/:previewKey

Solicita a remoção imediata do preview e encerra sua cobrança quando a remoção for confirmada. A operação é idempotente: repetir o delete não cria outro ambiente nem outra cobrança.

curl -sS -X DELETE \
  "$BASE_URL/project/$PROJECT_ID/preview-environments/pr-42" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

A API responde 202 com { "status": "accepted", "data": { "operation": {...}, "preview": {...} } }. Quando o preview já estiver removido, a repetição retorna o estado terminal ou uma resposta de sucesso equivalente. A Action não exige IMAGE para este caminho.

Polling de operações

Consultar uma operação

GET /project/:projectId/preview-environments/:previewKey/operations/:operationId

Exige project.preview.deploy. Use o operation_id retornado em data.operation por PUT ou DELETE para acompanhar a operação. Consulte em intervalos limitados e pare em um estado terminal.

Estados possíveis:

  • accepted
  • reserving
  • provisioning
  • updating
  • available
  • deleting
  • deleted
  • failed

Upsert termina com sucesso em available; delete termina com sucesso em deleted. Em failed, leia o código público e corrija a entrada antes de tentar novamente.

curl -sS \
  "$BASE_URL/project/$PROJECT_ID/preview-environments/pr-42/operations/operation-id" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "x-organization-id: $ORGANIZATION_ID"

A resposta de operação contém somente estado, identificadores públicos, timestamps, URL quando disponível, expires_at e erro público sanitizado. Não contém segredos ou detalhes internos.

Erros públicos

Os erros usam { "status": "failed", "code": "...", "message": "..." }. Os códigos permanecem estáveis e a mensagem é acionável:

StatusCódigoQuando ocorre
400preview_disabledOs Ambientes de Preview não estão habilitados para o projeto ou a organização. Também vale para operações com API Key da organização enquanto o opt-in estiver desligado
400preview_plan_not_allowed, preview_ttl_invalid, preview_ttl_exceeds_limit, preview_limit_invalidPlano, duração ou limite fora do permitido
409PARENT_CONFIGURATION_UNAVAILABLEO projeto principal não tem configuração pública suficiente para aplicar o preview
409PREVIEW_OPERATION_CONFLICTJá existe uma operação ativa e incompatível para a mesma identidade
409PREVIEW_ORGANIZATION_LIMIT_REACHED, PREVIEW_PROJECT_LIMIT_REACHEDO limite efetivo da organização ou do projeto foi atingido
502PREVIEW_PROVISIONING_FAILEDO preview não pôde ser provisionado
503ORGANIZATION_RUNTIME_UNAVAILABLEO ambiente da organização está temporariamente indisponível; tente novamente em instantes

preview_wait_timeout é reportado pela Action oficial quando ela atinge o tempo máximo de espera; a API não retorna esse código. Nunca exponha a resposta completa em logs públicos quando ela fizer parte de uma automação.

Status HTTP

  • 200: leitura bem-sucedida.
  • 202: upsert ou delete aceito para processamento, sempre com { "status": "accepted", "data": { "operation", "preview" } }.
  • 400: body, chave, ação, duração inválidos ou opt-in desligado.
  • 401: credencial ausente ou inválida.
  • 403: organização, projeto ou permissão insuficiente.
  • 404: projeto principal, preview ou operação não encontrada.
  • 409: conflito com uma operação ativa, payload incompatível, limite atingido ou configuração do projeto principal indisponível.
  • 502, 503: falha ao provisionar o preview ou ambiente da organização temporariamente indisponível.

Limites de requisições (contados por IP de origem): leitura da lista 50 por minuto; leitura de um preview 100 por minuto; PUT e DELETE 10 por minuto; consulta de operação 120 por minuto; custos 30 por minuto.

Próximos passos

Última atualização em

Nessa página