{
  "info": {
    "name": "Konstruct API — Application Instances (blue/green)",
    "description": "Deploy multiple named instances of the same application and switch live traffic between them (blue/green), using the Konstruct API.\n\nMODEL:\n- An instance is created through the normal deploy flow (POST /application-deployment/deploy) with an `instance_name` field. Omitting it (or using \"default\") deploys the primary instance. Deploying the same application to the same environment and cluster with a different `instance_name` creates a second instance.\n- Once two or more instances exist, use the per-environment route endpoints to point or flip live traffic between them.\n\nTYPICAL FLOW: deploy default → deploy green → configure route (active=default) → switch traffic to green.\n\nNAMESPACE: pass `environment_namespace` on deploy — that is the namespace the instance workloads (Deployment/Service) land in. The per-environment route is co-located there automatically. Omit it only for legacy default-scoped environments.\n\nPORT: the route's `port` must match the instance Service port (derived from the chart's `service.port`). Set `routePort` to the app's listen port — for example 3000 or 8080. Default 80.\n\nAUTH: set `token` to a Konstruct API key (konst_api_… — not an MCP key) or a session JWT. Never commit a real key back into this file.\n\nVariables: baseUrl, token, namespace, appName, environment, envNamespace, cluster, version, instanceName, hostname, gatewayName, gatewayNamespace, gatewayClass, routePort.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{token}}", "type": "string" }] },
  "variable": [
    { "key": "baseUrl", "value": "https://konstruct.example.com", "type": "string" },
    { "key": "token", "value": "", "type": "string" },
    { "key": "namespace", "value": "your-org", "type": "string" },
    { "key": "appName", "value": "my-app", "type": "string" },
    { "key": "environment", "value": "my-environment", "type": "string" },
    { "key": "envNamespace", "value": "default", "type": "string" },
    { "key": "cluster", "value": "my-workload-cluster", "type": "string" },
    { "key": "version", "value": "0.1.0", "type": "string" },
    { "key": "instanceName", "value": "green", "type": "string" },
    { "key": "hostname", "value": "my-app.example.com", "type": "string" },
    { "key": "gatewayName", "value": "eg", "type": "string" },
    { "key": "gatewayNamespace", "value": "default", "type": "string" },
    { "key": "gatewayClass", "value": "", "type": "string" },
    { "key": "routePort", "value": "3000", "type": "string" }
  ],
  "item": [
    {
      "name": "Deploy",
      "item": [
        {
          "name": "Deploy default instance",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('2xx', () => pm.expect(pm.response.code).to.be.oneOf([200,201]));"
          ] } }],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"application_name\": \"{{appName}}\",\n  \"namespace\": \"{{namespace}}\",\n  \"cluster_name\": \"{{cluster}}\",\n  \"environment_name\": \"{{environment}}\",\n  \"environment_namespace\": \"{{envNamespace}}\",\n  \"version\": \"{{version}}\"\n}" },
            "url": {
              "raw": "{{baseUrl}}/api/v1/application-deployment/deploy",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "application-deployment", "deploy"]
            },
            "description": "Deploys the primary instance. `instance_name` is omitted, so it defaults to \"default\" and the deployment keeps the historical name {app}-{env}-{cluster}. `environment_namespace` is the namespace the workloads (Deployment/Service) land in — the route co-locates there so its backendRef resolves. With only one instance there is nothing to switch."
          }
        },
        {
          "name": "Deploy green instance",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('2xx', () => pm.expect(pm.response.code).to.be.oneOf([200,201]));"
          ] } }],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"application_name\": \"{{appName}}\",\n  \"namespace\": \"{{namespace}}\",\n  \"cluster_name\": \"{{cluster}}\",\n  \"environment_name\": \"{{environment}}\",\n  \"environment_namespace\": \"{{envNamespace}}\",\n  \"version\": \"{{version}}\",\n  \"instance_name\": \"{{instanceName}}\"\n}" },
            "url": {
              "raw": "{{baseUrl}}/api/v1/application-deployment/deploy",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "application-deployment", "deploy"]
            },
            "description": "Deploys a second instance named by {{instanceName}} (deployment {app}-{instance}-{env}-{cluster}) into the same environment_namespace as the default instance, so both are fronted by one route. With two instances, traffic switching becomes available via the Route endpoints."
          }
        },
        {
          "name": "Delete default instance deployment",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('204', () => pm.response.to.have.status(204));"
          ] } }],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/application-deployment/{{namespace}}/{{appName}}-{{environment}}-{{cluster}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "application-deployment", "{{namespace}}", "{{appName}}-{{environment}}-{{cluster}}"]
            },
            "description": "Deletes the primary instance's ApplicationDeployment. The name is the default form {app}-{env}-{cluster} with no instance segment. The deployment's manifest is removed from the GitOps repository and Argo CD prunes the workload. Returns 204 No Content."
          }
        },
        {
          "name": "Delete green instance deployment",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('204', () => pm.response.to.have.status(204));"
          ] } }],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/application-deployment/{{namespace}}/{{appName}}-{{instanceName}}-{{environment}}-{{cluster}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "application-deployment", "{{namespace}}", "{{appName}}-{{instanceName}}-{{environment}}-{{cluster}}"]
            },
            "description": "Deletes a non-default instance's ApplicationDeployment. The name carries the instance segment {app}-{instance}-{env}-{cluster}. The matching per-instance manifest is removed from the GitOps repository and Argo CD prunes the workload. Returns 204 No Content."
          }
        }
      ]
    },
    {
      "name": "Route",
      "item": [
        {
          "name": "Configure route (PUT)",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('200', () => pm.response.to.have.status(200));",
            "pm.test('active default', () => pm.expect(pm.response.json().active).to.eql('default'));"
          ] } }],
          "request": {
            "method": "PUT",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"hostname\": \"{{hostname}}\",\n  \"gateway\": {\n    \"name\": \"{{gatewayName}}\",\n    \"namespace\": \"{{gatewayNamespace}}\",\n    \"class_name\": \"{{gatewayClass}}\"\n  },\n  \"active\": \"default\",\n  \"port\": {{routePort}},\n  \"cluster_name\": \"{{cluster}}\"\n}" },
            "url": {
              "raw": "{{baseUrl}}/api/v1/konstruct-application/{{namespace}}/{{appName}}/environments/{{environment}}/route",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "konstruct-application", "{{namespace}}", "{{appName}}", "environments", "{{environment}}", "route"]
            },
            "description": "Creates or updates the environment's HTTPRoute (idempotent). `hostname` and `gateway` are the only non-derivable inputs. `port` is the backendRef port and must match the instance Service port (chart `service.port`). `active` must be an already-deployed instance. The route is committed into the environment's namespace so its backendRef resolves to the instance Services. Changes are committed to the application's GitOps repository and reconciled by Argo CD."
          }
        },
        {
          "name": "Get route",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('200', () => pm.response.to.have.status(200));",
            "pm.test('has active', () => pm.expect(pm.response.json()).to.have.property('active'));"
          ] } }],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/konstruct-application/{{namespace}}/{{appName}}/environments/{{environment}}/route?cluster_name={{cluster}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "konstruct-application", "{{namespace}}", "{{appName}}", "environments", "{{environment}}", "route"],
              "query": [{ "key": "cluster_name", "value": "{{cluster}}", "description": "Optional. Workload cluster within the environment. Pass it to target a specific cluster; disable this param to let the API derive it from the Environment resource." }]
            },
            "description": "Returns the hostname, gateway, and active instance. 404 if no route has been configured yet. Pass `cluster_name` to target the workload cluster within the environment; without it the API derives the cluster from the Environment resource in the app's namespace."
          }
        },
        {
          "name": "Switch traffic",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('200', () => pm.response.to.have.status(200));",
            "pm.test('now green', () => pm.expect(pm.response.json().active).to.eql('green'));"
          ] } }],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"target\": \"{{instanceName}}\",\n  \"cluster_name\": \"{{cluster}}\"\n}" },
            "url": {
              "raw": "{{baseUrl}}/api/v1/konstruct-application/{{namespace}}/{{appName}}/environments/{{environment}}/route/switch",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "konstruct-application", "{{namespace}}", "{{appName}}", "environments", "{{environment}}", "route", "switch"]
            },
            "description": "Flips the route to the target instance and commits the change. No pods restart; rollback is a git revert. `target` must be an already-deployed instance. Pass `cluster_name` to target the workload cluster within the environment."
          }
        },
        {
          "name": "Delete route (DELETE)",
          "event": [{ "listen": "test", "script": { "type": "text/javascript", "exec": [
            "pm.test('200', () => pm.response.to.have.status(200));",
            "pm.test('returns removed route state', () => pm.expect(pm.response.json()).to.have.property('active'));"
          ] } }],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/konstruct-application/{{namespace}}/{{appName}}/environments/{{environment}}/route?cluster_name={{cluster}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "konstruct-application", "{{namespace}}", "{{appName}}", "environments", "{{environment}}", "route"],
              "query": [{ "key": "cluster_name", "value": "{{cluster}}", "description": "Optional. Workload cluster within the environment (derived from the Environment when omitted). Disable this param to let the API derive it." }]
            },
            "description": "Removes the environment's HTTPRoute (and its gateway/route resources) by committing their deletion to the application's GitOps repository; Argo CD then prunes them from the workload cluster. Returns the removed route's state (active instance, hostname, gateway). 404 if no route is configured. Requires Platform Admin or Team Admin."
          }
        }
      ]
    }
  ]
}
