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:
| Header | Obrigatório | Descrição |
|---|---|---|
x-api-key | Nas operações de automação | API Key da organização, mantida em um secret. |
x-organization-id | Com token de usuário | Organização ativa do projeto. A API Key da organização já está vinculada à organização. |
Content-Type: application/json | Em requests com body | Indica 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/v1Nos 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
| Objetivo | Método e rota |
|---|---|
| Consultar settings | GET /project/:projectId/preview-environments/settings |
| Atualizar settings | PATCH /project/:projectId/preview-environments/settings |
| Listar plano herdado | GET /project/:projectId/preview-environments/plans |
| Consultar custos dos previews | GET /project/:projectId/preview-environments/billing |
| Listar previews | GET /project/:projectId/preview-environments |
| Criar ou atualizar um preview | PUT /project/:projectId/preview-environments/:previewKey |
| Consultar um preview | GET /project/:projectId/preview-environments/:previewKey |
| Remover um preview | DELETE /project/:projectId/preview-environments/:previewKey |
| Consultar uma operação | GET /project/:projectId/preview-environments/:previewKey/operations/:operationId |
Settings do projeto
Consultar settings
GET /project/:projectId/preview-environments/settingsRetorna 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/settingsRequer 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/billingRequer 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/plansRetorna 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-environmentsLista 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:
| Campo | Descrição |
|---|---|
id | Identificador público do preview. |
key | Chave estável que identifica o ambiente no projeto. |
status | Estado de produto, como accepted, provisioning, available, deleting, deleted ou failed. |
url | URL pública quando disponível. |
plan | Plano selecionado. |
payment_mode | O preview usa cobrança hourly. |
exposure | Exposição configurada para o ambiente. |
inherit_envs | Sempre true: os ENVs do projeto principal são herdados. Nunca contém os valores. |
updated_at e expires_at | Atualizaçã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/:previewKeyCria ou atualiza o preview identificado por previewKey. O corpo de um upsert aceita:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
image | string | Sim no upsert | Referência da imagem pronta a publicar (até 2.048 caracteres). |
inherit_envs | boolean | Não | Campo de compatibilidade legada; o Preview sempre herda os ENVs do usuário dentro da Zenifra. |
ttl_hours | integer | Não | Duração em horas; default 24, mínimo 1, máximo 168. |
source | object | Não | Metadados 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/:previewKeyExige 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/:previewKeySolicita 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/:operationIdExige 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:
acceptedreservingprovisioningupdatingavailabledeletingdeletedfailed
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:
| Status | Código | Quando ocorre |
|---|---|---|
400 | preview_disabled | Os 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 |
400 | preview_plan_not_allowed, preview_ttl_invalid, preview_ttl_exceeds_limit, preview_limit_invalid | Plano, duração ou limite fora do permitido |
409 | PARENT_CONFIGURATION_UNAVAILABLE | O projeto principal não tem configuração pública suficiente para aplicar o preview |
409 | PREVIEW_OPERATION_CONFLICT | Já existe uma operação ativa e incompatível para a mesma identidade |
409 | PREVIEW_ORGANIZATION_LIMIT_REACHED, PREVIEW_PROJECT_LIMIT_REACHED | O limite efetivo da organização ou do projeto foi atingido |
502 | PREVIEW_PROVISIONING_FAILED | O preview não pôde ser provisionado |
503 | ORGANIZATION_RUNTIME_UNAVAILABLE | O 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