Managing Resources

Environments

Manage a tenant's dev/staging/production environments — lifecycle, the default and production flags, protection policy, readiness validation, comparison, and artifact/provider bindings.

A tenant is one isolation boundary; an environment is a partition within that boundary. Environments let a single tenant separate development, staging, and production work — each with its own artifact bindings, provider bindings, credential-visibility rules, and mutation policy — so that promoting a workflow from staging to production is a governed step rather than an in-place edit to live config.

Every tenant has exactly one default environment; unqualified reads and writes resolve against it. Production environments are additionally marked with a production flag that tightens what may change and how.

Where it lives

Environments are served by EnvironmentService under /api/v2/environments. The pure-domain contracts are in domain/environment/types.go; the application aggregate is application/environment/service.go. Reads require environment:read, mutations require environment:write, and toggling the production flag requires the elevated environment:admin scope.

The environment object

Prop

Type

The protection policy

EnvironmentPolicy is the knob-set that governs whether changes to an environment are allowed directly, must go through promotion, and how credentials are exposed. When you create an environment without a policy, Ductor derives sensible defaults from the purpose.

Prop

Type

Read the knobs as a gate sequence rather than a flat list — they answer one question in order, and a production environment simply has stricter answers:

no yes yes no no yes yes no change an artifact mutable? rejected, frozen allow_direct_mutation? edit in place require_promotion? require_certification? certify first promote in

The defaults are purpose-driven. A non-production environment defaults to mutable, direct mutation allowed, live provider calls allowed, metadata_only credential visibility, and scoped_writers. A production environment flips to: no direct mutation, promotion required, certification required, redacted credentials, and promotion_only writes. The domain further rejects incoherent production policies — for example, a production environment that allows direct mutation but does not require certification is invalid.

Lifecycle

Create

CreateEnvironmentPOST /api/v2/environments (environment:write). Only key is required; display_name, purpose, policy, and default are optional. Responses carry metadata and policy only — credentials, API-key plaintext, and provider tokens are never returned.

curl -s -X POST https://api.ductor.io/api/v2/environments \
  -H "Authorization: Bearer $DUCTOR_TOKEN" \
  -H "X-Tenant-ID: $DUCTOR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{ "key": "staging", "display_name": "Staging", "purpose": "staging" }'

Read, update, list

GetEnvironment (GET /api/v2/environments/{environment}), ListEnvironments (GET /api/v2/environments), and UpdateEnvironment (PATCH /api/v2/environments/{environment}) cover reads and metadata/policy edits. ListEnvironments filters by status, purpose, production_only, and include_archived. The {environment} path segment accepts either the key or the ID.

Set the default

SetDefaultEnvironmentPOST /api/v2/environments/{environment}:set-default (environment:write) — moves the tenant's default. Because a tenant must always have exactly one default, this is an atomic switch, not an additive flag.

Set the production flag

SetProductionFlagPOST /api/v2/environments/{environment}:set-production (environment:admin) — marks or unmarks an environment as production and updates its policy semantics atomically. This is the one environment operation that requires environment:admin rather than environment:write.

curl -s -X POST "https://api.ductor.io/api/v2/environments/production:set-production" \
  -H "Authorization: Bearer $DUCTOR_TOKEN" \
  -H "X-Tenant-ID: $DUCTOR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{ "environment": "production", "production": true }'

Archive

ArchiveEnvironmentPOST /api/v2/environments/{environment}:archive (environment:write) — archives a non-default environment. Archived environments fail closed for mutable artifact bindings: they stop accepting the artifact changes an active environment would.

Readiness and comparison

Environments exist so that promoting change is deliberate. Two operations support that governance directly.

Validate readiness

ValidateEnvironmentReadinessPOST /api/v2/environments/{environment}:validate-readiness (environment:read) — answers "can this environment safely accept governed changes right now?" It returns an EnvironmentReadinessReport:

Prop

Type

Use it as the gate before a promotion: a non-empty blocking_reasons means the target environment is not in a state to receive the change.

Compare two environments

CompareEnvironmentsGET /api/v2/environments:compare?from={a}&to={b} (environment:read) — diffs the artifact bindings between two environments and returns redacted added / removed / changed bindings, an allowed verdict, and any blocking_reasons. This is what you inspect before promoting to see exactly what would move.

curl -s "https://api.ductor.io/api/v2/environments:compare?from=staging&to=production" \
  -H "Authorization: Bearer $DUCTOR_TOKEN" \
  -H "X-Tenant-ID: $DUCTOR_TENANT_ID"

Bindings

An environment is bound to the artifacts and providers it runs.

  • Artifact bindingsListEnvironmentArtifactBindings (GET /api/v2/environments/{environment}/artifact-bindings, environment:read) — list the redacted artifacts pinned to the environment: workflow definitions, connector deployments and connections, runtime-config refs, policy packs, promotion candidates, schedule triggers, and more. The runtime-config ref kind is how a resolved runtime configuration is attached to an environment. Filter by artifact_kind and artifact_id.
  • Provider bindingsListProviderEnvironmentBindings (GET /api/v2/environments/{environment}/provider-bindings, environment:read) — list explicit provider bindings for sandbox, staging, and production environments. Provider credentials and tokens are never returned. Filter by canonical_provider_key, purpose, and status (available, needs_review, or unsupported).

Provider-binding validation enforces environment hygiene: a production binding may not execute a sandbox or staging provider key, and sandbox/staging bindings must record a distinct provider key when marked available. These guards keep a "production" environment from quietly pointing at non-production infrastructure.

Operations at a glance

OperationMethod & pathScope
List environmentsGET /api/v2/environmentsenvironment:read
Create environmentPOST /api/v2/environmentsenvironment:write
Get environmentGET /api/v2/environments/{environment}environment:read
Update environmentPATCH /api/v2/environments/{environment}environment:write
Set defaultPOST /api/v2/environments/{environment}:set-defaultenvironment:write
Set production flagPOST /api/v2/environments/{environment}:set-productionenvironment:admin
ArchivePOST /api/v2/environments/{environment}:archiveenvironment:write
Validate readinessPOST /api/v2/environments/{environment}:validate-readinessenvironment:read
CompareGET /api/v2/environments:compareenvironment:read
List artifact bindingsGET /api/v2/environments/{environment}/artifact-bindingsenvironment:read
List provider bindingsGET /api/v2/environments/{environment}/provider-bindingsenvironment:read

Where to go next