/api/v1. The tc CLI uses this API directly.
Authentication
Send your CLI API key in theX-API-Key header on every resource request:
POST /api/v1/api-keys. An API key cannot create another API key.
tc auth login completes the device flow, creates an API key, and stores it locally. tc auth logout only removes the local credentials.
Create an API key
name is required and can contain up to 32 characters. The response contains the secret once:
Authorization and service identity
Roles are global for the current Techulus Cloud installation. There are no project-level permissions.reader,developer, andadmincan read resources.developerandadmincan change configuration and deploy services.
target with the containing project, environment, and service labels.
Errors
Every API error uses the same shape:code for automation. Do not match the human-readable message.
Identity and collections
Collection responses use an opaque keyset cursor:
nextCursor as ?cursor=.... limit defaults to 100 and accepts values from 1 through 100.
Service resources
The paths in this table are relative to/api/v1/services/{serviceId}.
Rollout and build collections accept
limit from 1 through 100 and an opaque cursor. Their default limit is 25. Revisions accept their returned opaque cursor and return up to 25 items.
Configuration
GET /configuration returns these distinct states:
currentis the mutable configuration stored for the service.activeis the immutable specification used by the active deployment.activeRevisionIdandactiveDeploymentIdidentify that active state.hasPendingChangesandchangescompare current and active state.management.patchableandmanagement.blockersexplain whether the API can safely manage the service.
current.source. Its active.source comes from the immutable service revision used by the active deployment. The public projection includes the snapshotted repository, branch, and root directory. It omits repository IDs and authentication details.
Configuration and revision responses never include secret names, values, or ciphertext.
Replace configuration
POST /configuration/plan accepts the same complete desired configuration as PUT /configuration. It performs no writes and returns the authoritative target, action, currentVersion, desiredVersion, and structured changes (field, from, and to). Service IDs on these flat service routes are authorized installation-globally rather than being scoped by a project ID in the URL.
PUT /configuration is atomic and replaces the complete managed configuration. Send the currentVersion returned by the plan as one quoted strong ETag (for example, If-Match: "sha256:…"). Missing, unquoted, multiple, weak, or otherwise invalid headers are rejected; a service change after planning returns 409 CONFIGURATION_PLAN_STALE. A successful response returns the authoritative target and the structured change set that was applied. The request must contain exactly name, source, hostname, ports, placement, healthCheck, startCommand, and resources. Omitted or unknown fields are rejected. hostname must be concrete and non-null. Use null to clear nullable fields, including resources.
Replacing the final public HTTP port with a domain automatically disables serverless in the mutable service configuration. The plan reports this side effect as a serverless.enabled change before apply. You do not send serverless settings in the replacement request.
tc apply command sends this complete replacement. A linked techulus.yml stores only target.serviceId; desired service configuration remains under service. Explicit CLI targeting uses --service <serviceId>. During interactive tc link, a project with exactly one environment selects it automatically; zero environments is an error and multiple environments prompt for a choice.
The API supports these source variants:
github.com URLs. rootDir is required and must either stay inside the repository or be null to clear an existing build root. Source conversion and GitHub repository switching are not supported.
Use automatic placement for stateless services:
replicas with a range:
current.placement and the deployed policy plus concrete active target in
active.placement. Policy changes participate in plan/apply fingerprints.
To disable autoscaling, send the fixed automatic-placement form with replicas.
Use manual placement to choose exact servers:
placement; the API rejects a top-level replicas field.
CLI manifests remain fixed-replica only in V1. Configure autoscaling through the
dashboard or public configuration API. tc apply continues to send the fixed
replica manifest contract.
The API only manages stateless services with HTTP ports. Existing volumes, stateful mode, TCP or UDP ports, TLS passthrough, or invalid resource limits return a conflict with an actionable code.
Deployments and builds
POST /deploy uses the persisted service source. It does not apply configuration first.
- An image service queues a rollout.
- A GitHub service queues a build. A rollout starts after a successful build.
status: "migration_started" and rolloutId: null. GitHub returns:
buildId is initially null. /status reports latestBuild and latestRollout independently.
Each GitHub deployment resolves an exact 40-character commit before it queues build work. The control plane creates an immutable service revision that snapshots the service configuration, source provenance, and reserved artifact identity. Every platform build references that revision and reads its repository, branch, commit, root directory, authentication mode, secrets, and final image URI from the revision.
After all platform images succeed, the control plane creates the final manifest and rolls out that same revision. Configuration changes made while a build is running do not alter its inputs. Retrying a failed or cancelled build creates a new revision with a new artifact identity. It never overwrites an artifact reserved by an earlier revision.
Logs
Service logs accept these query parameters:
Round-trip
nextCursor without decoding or modifying it. When hasMore is true, request the next page immediately. Otherwise, respect pollAfterMs before the next request. Keep the service, q, and range unchanged while reusing a cursor.
provider: "disabled" with an empty list. An upstream failure returns 502 LOG_PROVIDER_ERROR. Log following returns 409 LOG_CURSOR_UNAVAILABLE if an agent must be upgraded before it can provide deterministic cursors.
Rollout logs accept q and limit. Their response includes bounded stage messages for the contained rollout.
Metrics
Metrics acceptrange=1h|6h|24h|7d|30d.
- A configured provider returns
{ "provider": "enabled", "metrics": ... }.metricscan contain successful empty series. - A disabled provider returns
{ "provider": "disabled", "metrics": null }. - An upstream failure returns
502 METRICS_PROVIDER_ERROR.
CLI commands
The CLI uses the same endpoints documented above:tc link stores only the selected target.serviceId in techulus.yml. Relinking a manifest to a different service requires removing target.serviceId first. tc apply always displays the server-generated plan and prompts before writing; use tc apply --yes for noninteractive automation. Image and GitHub services use the same tc link, tc apply, tc deploy, and inspection commands.