curl --request POST \
--url https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "<string>",
"owner_approved": true,
"target_release": "<string>",
"dry_run": true,
"offline": true,
"stackkit": "<string>",
"candidate_spec": {},
"rollback_target_ref": "<string>",
"snapshot_anchor_id": "<string>",
"restore_result_id": "<string>",
"activation_operation_id": "<string>",
"restore_plan_hash": "<string>",
"ai_provider_base_url": "<string>",
"wallet_item_id": "<string>",
"wallet_item_rotate": true,
"ai_provider_disable": true
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations"
payload = {
"agent_id": "<string>",
"owner_approved": True,
"target_release": "<string>",
"dry_run": True,
"offline": True,
"stackkit": "<string>",
"candidate_spec": {},
"rollback_target_ref": "<string>",
"snapshot_anchor_id": "<string>",
"restore_result_id": "<string>",
"activation_operation_id": "<string>",
"restore_plan_hash": "<string>",
"ai_provider_base_url": "<string>",
"wallet_item_id": "<string>",
"wallet_item_rotate": True,
"ai_provider_disable": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: '<string>',
owner_approved: true,
target_release: '<string>',
dry_run: true,
offline: true,
stackkit: '<string>',
candidate_spec: {},
rollback_target_ref: '<string>',
snapshot_anchor_id: '<string>',
restore_result_id: '<string>',
activation_operation_id: '<string>',
restore_plan_hash: '<string>',
ai_provider_base_url: '<string>',
wallet_item_id: '<string>',
wallet_item_rotate: true,
ai_provider_disable: true
})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'agent_id' => '<string>',
'owner_approved' => true,
'target_release' => '<string>',
'dry_run' => true,
'offline' => true,
'stackkit' => '<string>',
'candidate_spec' => [
],
'rollback_target_ref' => '<string>',
'snapshot_anchor_id' => '<string>',
'restore_result_id' => '<string>',
'activation_operation_id' => '<string>',
'restore_plan_hash' => '<string>',
'ai_provider_base_url' => '<string>',
'wallet_item_id' => '<string>',
'wallet_item_rotate' => true,
'ai_provider_disable' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations"
payload := strings.NewReader("{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"job_id": "<string>",
"kit_deployment_id": "<string>",
"agent_id": "<string>",
"operation": "<string>",
"status": "<string>"
},
"meta": {
"total": 123,
"page": 123,
"per_page": 123,
"managed_runtime_inventory_complete": true,
"worker_inventory_sha256": "<string>",
"managed_runtime_active_lease_ids": [
"<string>"
],
"managed_runtime_inactive_lease_ids": [
"<string>"
],
"managed_runtime_lease_generation_digests": [
{
"lease_id": "<string>",
"resource_generation_digest": "<string>"
}
],
"managed_runtime_duplicate_lease_ids": [
"<string>"
],
"managed_runtime_attachment_conflict_lease_ids": [
"<string>"
]
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}Queue an owned node's typed Advanced or backup operation
Uses the same tenant- and owner-scoped dispatcher as the operator UI. The node executes through its authenticated channel, current release pin, native Advanced catalog and issued operation capability. Techstack never executes Terramate, apply, rollback, backup or restore itself. A mutation requires owner_approved; service locks and active server maintenance are checked before enqueue. Direct backup_run and backup_configure remain Basement-only; managed kits keep their schedule and sealed target-renewal authority. backup_configure derives the node’s target and plan from existing custody and accepts no credential fields. advanced_change_set requires candidate_spec; rollback requires an exact rollback_target_ref; restore_drill may reuse a snapshot_anchor_id. ai_provider lets Private AI offer an external OpenAI-compatible provider: the kombify Wallet seals the item wallet_item_id (the provider’s API key) to the node, which must be listed as a host target of that item, the node binds it to ai_provider_base_url, and a drift reconcile applies the setting. ai_provider_disable removes it. Restore activation requires exactly one Idempotency-Key header, while other operations have no replay guarantee. Acceptance is not execution success; read the returned job and its scoped result to observe effects.
curl --request POST \
--url https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "<string>",
"owner_approved": true,
"target_release": "<string>",
"dry_run": true,
"offline": true,
"stackkit": "<string>",
"candidate_spec": {},
"rollback_target_ref": "<string>",
"snapshot_anchor_id": "<string>",
"restore_result_id": "<string>",
"activation_operation_id": "<string>",
"restore_plan_hash": "<string>",
"ai_provider_base_url": "<string>",
"wallet_item_id": "<string>",
"wallet_item_rotate": true,
"ai_provider_disable": true
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations"
payload = {
"agent_id": "<string>",
"owner_approved": True,
"target_release": "<string>",
"dry_run": True,
"offline": True,
"stackkit": "<string>",
"candidate_spec": {},
"rollback_target_ref": "<string>",
"snapshot_anchor_id": "<string>",
"restore_result_id": "<string>",
"activation_operation_id": "<string>",
"restore_plan_hash": "<string>",
"ai_provider_base_url": "<string>",
"wallet_item_id": "<string>",
"wallet_item_rotate": True,
"ai_provider_disable": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: '<string>',
owner_approved: true,
target_release: '<string>',
dry_run: true,
offline: true,
stackkit: '<string>',
candidate_spec: {},
rollback_target_ref: '<string>',
snapshot_anchor_id: '<string>',
restore_result_id: '<string>',
activation_operation_id: '<string>',
restore_plan_hash: '<string>',
ai_provider_base_url: '<string>',
wallet_item_id: '<string>',
wallet_item_rotate: true,
ai_provider_disable: true
})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'agent_id' => '<string>',
'owner_approved' => true,
'target_release' => '<string>',
'dry_run' => true,
'offline' => true,
'stackkit' => '<string>',
'candidate_spec' => [
],
'rollback_target_ref' => '<string>',
'snapshot_anchor_id' => '<string>',
'restore_result_id' => '<string>',
'activation_operation_id' => '<string>',
'restore_plan_hash' => '<string>',
'ai_provider_base_url' => '<string>',
'wallet_item_id' => '<string>',
'wallet_item_rotate' => true,
'ai_provider_disable' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations"
payload := strings.NewReader("{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/stacks/{id}/stackkit/operations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"agent_id\": \"<string>\",\n \"owner_approved\": true,\n \"target_release\": \"<string>\",\n \"dry_run\": true,\n \"offline\": true,\n \"stackkit\": \"<string>\",\n \"candidate_spec\": {},\n \"rollback_target_ref\": \"<string>\",\n \"snapshot_anchor_id\": \"<string>\",\n \"restore_result_id\": \"<string>\",\n \"activation_operation_id\": \"<string>\",\n \"restore_plan_hash\": \"<string>\",\n \"ai_provider_base_url\": \"<string>\",\n \"wallet_item_id\": \"<string>\",\n \"wallet_item_rotate\": true,\n \"ai_provider_disable\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"job_id": "<string>",
"kit_deployment_id": "<string>",
"agent_id": "<string>",
"operation": "<string>",
"status": "<string>"
},
"meta": {
"total": 123,
"page": 123,
"per_page": 123,
"managed_runtime_inventory_complete": true,
"worker_inventory_sha256": "<string>",
"managed_runtime_active_lease_ids": [
"<string>"
],
"managed_runtime_inactive_lease_ids": [
"<string>"
],
"managed_runtime_lease_generation_digests": [
{
"lease_id": "<string>",
"resource_generation_digest": "<string>"
}
],
"managed_runtime_duplicate_lease_ids": [
"<string>"
],
"managed_runtime_attachment_conflict_lease_ids": [
"<string>"
]
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}Authorizations
OIDC/JWKS bearer token. Self-hosted defaults to Pocket ID; SaaS uses Auth0 through the edge. PocketBase JWT is legacy migration compatibility only.
Headers
Required for backup_restore_activate; derived identity binds durable replay.
1 - 128Path Parameters
Stack ID
Body
1plan, apply, verify, upgrade, drift_detect, drift_reconcile, advanced_change_set, rollback, restore_drill, backup_run, backup_configure, backup_status, backup_restore, backup_restore_activate, backup_restore_recover, ai_provider Optional execution binding; normally derived from the stack's managed rollout.
Canonical candidate StackSpec validated by the pinned node executor; required for advanced_change_set.
Exact executor-state snapshot or change-set digest.
^sha256:[a-f0-9]{64}$^sha256:[a-f0-9]{64}$^sha256:[a-f0-9]{64}$^sha256:[a-f0-9]{64}$https base URL of the OpenAI-compatible provider API for ai_provider.
512kombify Wallet item holding the provider's API key for ai_provider.
^itm_[a-z2-7]{26}$Deliver a rotated item that replaces the version the node holds.
Remove the external provider instead of setting it.
