> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kombify.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Ensure the desired routing overlay for one exact StackKit deployment and Node

> Atomically persists an idempotent, revisioned routing overlay without mutating the user's immutable intent. server_id is always exact and mandatory. lease_id is mandatory for managed runtimes and omitted for a local/Basement runtime which has no lease. For a managed target, a true ensure_rollout request dispatches the existing deploy pipeline only after proving that its selected active foundation lease and canonical Node equal this exact target. The API never reports the resulting job as already applied. The overlay is consumed only while deriving StackKits artifacts and this path never creates or selects a replacement VM.



## OpenAPI

````yaml /techstack/reference/api/openapi.yaml put /api/v1/stacks/{id}/routing
openapi: 3.1.0
info:
  title: kombify-TechStack API
  description: >
    REST API for kombify-TechStack -- the hybrid cloud control plane for
    homelabs.


    kombify-TechStack manages infrastructure through a spec-driven architecture:

    validate YAML specs via CUE, generate OpenTofu configurations, and manage

    nodes through a gRPC agent protocol.


    ## Authentication


    Authenticated endpoints accept an OIDC/JWKS bearer token or an API key

    where documented. Self-hosted TechStack defaults to Pocket ID as identity

    provider. SaaS routes enter through the edge with Auth0 as the platform

    identity provider. PocketBase session exchange remains legacy migration

    compatibility only.


    ## Response Format


    **Success:** `{ "data": <object>, "meta": { "total": int, "page": int,
    "per_page": int } }`


    **Error:** `{ "error": { "code": "<ERROR_CODE>", "message": "...",
    "details": <any> } }`


    ## Pagination


    List endpoints accept `page` (default: 1) and `per_page` (default: 20, max:
    100) query parameters.
  version: 1.0.0
  contact:
    name: kombify
    url: https://kombify.io
  license:
    name: Apache-2.0 AND GPL-3.0
    url: https://github.com/KombiverseLabs/kombify-TechStack/blob/main/LICENSE
servers:
  - url: https://api.kombify.io/v1/techstack
    description: >-
      Production canonical (via Cloudflare edge gateway, strip-prefix). Clients
      MUST use this projection. The Gateway strips /v1/techstack and re-adds
      /api/v1 at the origin, so it resolves the /api/v1/* paths below cleanly.
  - url: http://localhost:5260
    description: Local development
  - url: https://techstack.kombify.io
    description: Production (direct, no Gateway prefix)
  - url: https://api.kombify.io/v1/orchestrator
    description: >-
      Legacy StackKit-Orchestrator projection of the same origin. RETAINED for
      backward compatibility with existing consumers only. Do NOT use for mobile
      or new clients: combined with the /api/v1/* paths it double-resolves
      (yielding /v1/orchestrator/api/v1/...). Prefer /v1/techstack.
security:
  - bearerAuth: []
tags:
  - name: Health
    description: Health checks and service info (no auth required)
  - name: Instance
    description: Local instance identity and enrollment metadata
  - name: Stacks
    description: Stack lifecycle management (create, provision, deploy, destroy)
  - name: Stacks - Specs
    description: Access persisted specification chain (intent, requirements, unified)
  - name: Stacks - Import/Export
    description: Import and export StackKits stack-spec.yaml configurations
  - name: Stacks - Drift
    description: Infrastructure drift detection and resolution
  - name: Unifier
    description: Spec validation, analysis, unification, and IaC generation pipeline
  - name: StackKits
    description: Infrastructure template catalog
  - name: Add-ons
    description: Add-on detection and registry
  - name: Workers
    description: Worker node registration and management
  - name: Servers
    description: Canonical server lifecycle, connection, and health state
  - name: Inventory
    description: >-
      Owner-scoped sanitized server and service read models for UI, API, and MCP
      clients
  - name: Pre-Checks
    description: Pre-deployment hardware and software validation
  - name: Agents
    description: Connected gRPC agent management and commands
  - name: Jobs
    description: Background job monitoring and SSE streaming
  - name: Discovery
    description: Network device discovery and SSH testing
  - name: Features
    description: Feature flags (read-only; managed centrally via the kombify Admin API)
  - name: Monthly Runtime
    description: Provider-free user API for subscription-backed stack runtime control
  - name: Runtime
    description: Recent runtime/deploy logs (job/deploy progress + container tail)
  - name: Wallet
    description: >-
      Redacted recovery-item wallet with biometric/platform-reauth-gated reveal.
      List responses strip secret/totp; reveal requires a fresh trusted-reauth
      HMAC proof (5-minute window) and is audited server-side.
  - name: Trust
    description: Pairing tokens for worker enrollment
  - name: Client Binding
    description: >-
      Short-lived HTTPS pairing for a second client and normal OIDC account
      handoff
  - name: Tunnel
    description: Cloudflare tunnel management for NAT traversal
  - name: Backups
    description: Database backup management (admin only)
  - name: Auth
    description: Authentication mode and SSO configuration
  - name: Metrics
    description: Prometheus-compatible instance metrics for admin/infra scrapers
  - name: Internal
    description: >-
      Internal SaaS-only APIs, including servicecall-protected executor
      contracts
paths:
  /api/v1/stacks/{id}/routing:
    put:
      tags:
        - Stacks
      summary: >-
        Ensure the desired routing overlay for one exact StackKit deployment and
        Node
      description: >-
        Atomically persists an idempotent, revisioned routing overlay without
        mutating the user's immutable intent. server_id is always exact and
        mandatory. lease_id is mandatory for managed runtimes and omitted for a
        local/Basement runtime which has no lease. For a managed target, a true
        ensure_rollout request dispatches the existing deploy pipeline only
        after proving that its selected active foundation lease and canonical
        Node equal this exact target. The API never reports the resulting job as
        already applied. The overlay is consumed only while deriving StackKits
        artifacts and this path never creates or selects a replacement VM.
      operationId: ensureStackRouting
      parameters:
        - $ref: '#/components/parameters/stackId'
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for safely replaying this exact routing mutation.
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - name: If-Match
          in: header
          required: false
          description: Optional optimistic-concurrency routing revision, for example `"3"`.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StackRoutingPutRequest'
      responses:
        '200':
          description: Desired routing state persisted; no rollout was requested.
          headers:
            ETag:
              description: Persisted routing revision.
              schema:
                type: string
                example: '"3"'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StackRoutingViewEnvelope'
        '202':
          description: >-
            Desired routing state persisted and an exact-target rollout job was
            enqueued; application remains pending.
          headers:
            ETag:
              description: Persisted routing revision.
              schema:
                type: string
                example: '"3"'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StackRoutingViewEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '412':
          description: If-Match does not equal the current routing revision.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          $ref: '#/components/responses/ValidationError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    stackId:
      name: id
      in: path
      required: true
      description: Stack ID
      schema:
        type: string
  schemas:
    StackRoutingPutRequest:
      type: object
      required:
        - server_id
        - mode
        - domain
        - provenance
      additionalProperties: false
      properties:
        server_id:
          type: string
          minLength: 1
          description: >-
            Exact canonical ServerRuntime target belonging to the stack and
            owner. For a managed lease this is the server_id exposed by the
            operations/ worker projection. If that read-model row is not present
            yet, TechStack may create only this deterministic ID from the
            validated exact lease.
        lease_id:
          type: string
          minLength: 1
          description: >-
            Exact RuntimeLease for a managed target. Omit for a local/Basement
            ServerRuntime that genuinely has no lease; invented leases are
            rejected.
        mode:
          type: string
          enum:
            - custom-domain
        domain:
          type: string
          minLength: 1
          description: >-
            Normalized custom domain; schemes, paths, ports, and wildcards are
            rejected.
          example: example.com
        provenance:
          $ref: '#/components/schemas/StackRoutingProvenance'
        ensure_rollout:
          type: boolean
          default: false
          description: >-
            Request reconciliation without implying that it has already been
            dispatched or applied.
    StackRoutingViewEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          $ref: '#/components/schemas/StackRoutingView'
        meta:
          type: object
          additionalProperties: true
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - INTERNAL_ERROR
                - NOT_FOUND
                - BAD_REQUEST
                - UNAUTHORIZED
                - FORBIDDEN
                - CONFLICT
                - VALIDATION_ERROR
                - RATE_LIMITED
                - SERVICE_UNAVAILABLE
                - METHOD_NOT_ALLOWED
            message:
              type: string
            details:
              description: Additional error context (validation errors, etc.)
    StackRoutingProvenance:
      type: object
      required:
        - source
        - dns_provider
      additionalProperties: false
      properties:
        source:
          type: string
          minLength: 1
          description: Product or operator flow which selected the domain.
          example: kombify-cloud
        dns_provider:
          type: string
          minLength: 1
          description: DNS authority used by the StackKit routing layer.
          example: cloudflare
        zone_id:
          type: string
          description: Non-secret provider zone reference, when one is known.
        external_domain_id:
          type: string
          description: Optional external product-domain reference for provenance.
    StackRoutingView:
      type: object
      required:
        - desired
        - observed
        - rollout
      properties:
        desired:
          $ref: '#/components/schemas/StackRoutingDesired'
        observed:
          $ref: '#/components/schemas/StackRoutingObserved'
        rollout:
          $ref: '#/components/schemas/StackRoutingRollout'
        idempotent_replay:
          type: boolean
          description: >-
            True when the same Idempotency-Key and semantic request were
            replayed.
    StackRoutingDesired:
      type: object
      required:
        - stack_id
        - server_id
        - revision
        - mode
        - domain
        - provenance
        - rollout_status
        - created_at
        - updated_at
      properties:
        stack_id:
          type: string
        server_id:
          type: string
        lease_id:
          type: string
          description: Present only when the exact target is lease-backed.
        revision:
          type: integer
          format: int64
          minimum: 1
        mode:
          type: string
          enum:
            - custom-domain
        domain:
          type: string
        provenance:
          $ref: '#/components/schemas/StackRoutingProvenance'
        rollout_status:
          type: string
          enum:
            - not_requested
            - pending
            - completed
            - failed
        rollout_job_id:
          type: string
        reason_code:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    StackRoutingObserved:
      type: object
      required:
        - status
        - applied
        - applied_revision
      properties:
        status:
          type: string
          enum:
            - unknown
            - pending
            - applied
            - failed
          description: >-
            Independent convergence state. A completed StackKit rollout remains
            pending until DNS, TLS, and runtime reachability are observed for
            the exact desired revision.
        applied:
          type: boolean
          description: False until a real observer proves this revision converged.
        applied_revision:
          type: integer
          format: int64
          minimum: 0
    StackRoutingRollout:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - not_requested
            - pending
            - completed
            - failed
        job_id:
          type: string
        reason_code:
          type: string
          description: >-
            Present only when a rollout cannot advance or has an explicit
            reason.
  responses:
    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: Request conflicts with existing state
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ValidationError:
      description: Request failed semantic validation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ServiceUnavailable:
      description: Required control-plane persistence or dependency is unavailable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        OIDC/JWKS bearer token. Self-hosted defaults to Pocket ID; SaaS uses
        Auth0 through the edge. PocketBase JWT is legacy migration compatibility
        only.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.