Skip to main content
The public API is available under /api/v1. The tc CLI uses this API directly.

Authentication

Send your CLI API key in the X-API-Key header on every resource request:
Browser cookies and bearer tokens cannot access resource endpoints. A bearer token or browser session can only create an API key with 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, and admin can read resources.
  • developer and admin can change configuration and deploy services.
Service operations use the globally unique service ID:
Nested project and environment paths remain available for browsing collections. Service responses include an authoritative target with the containing project, environment, and service labels.

Errors

Every API error uses the same shape:
Use code for automation. Do not match the human-readable message.

Identity and collections

Collection responses use an opaque keyset cursor:
Pass 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:
  • current is the mutable configuration stored for the service.
  • active is the immutable specification used by the active deployment.
  • activeRevisionId and activeDeploymentId identify that active state.
  • hasPendingChanges and changes compare current and active state.
  • management.patchable and management.blockers explain whether the API can safely manage the service.
A GitHub service keeps mutable repository settings in 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.
The 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 repository URLs are canonical HTTPS 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:
To autoscale an eligible service, replace fixed replicas with a range:
Autoscaling requires automatic placement, a stateless non-serverless service without volumes, and both CPU and memory limits. Minimum and maximum values must be from 1 through 32, with minimum no greater than maximum. CPU and memory use fixed 60% targets. Configuration responses expose the mutable policy in 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:
Manual placement requires online servers with WireGuard configured. Serverless services require proxy servers, including when automatic placement is used. A replacement that removes the final public HTTP domain can move the service to worker placement because the same update disables serverless. Automatic placement is not available for stateful or volume-backed services. Submit replica changes through 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.
Deploy responses are always HTTP 202:
Image migration can return status: "migration_started" and rolloutId: null. GitHub returns:
Build records are created asynchronously, so 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.
When logging is not configured, the response uses 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 accept range=1h|6h|24h|7d|30d.
  • A configured provider returns { "provider": "enabled", "metrics": ... }. metrics can contain successful empty series.
  • A disabled provider returns { "provider": "disabled", "metrics": null }.
  • An upstream failure returns 502 METRICS_PROVIDER_ERROR.
The endpoint exposes fixed service metrics. It does not accept raw PromQL.

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.