curl --request POST \
--url https://api.kombify.io/v1/techstack/api/v1/stacks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"stack_spec": {},
"user_config": {},
"user_config_raw": "<string>",
"provider": "<string>",
"services": [
"<string>"
],
"options": {
"enable_pocket_id": true,
"enable_pocketbase_backend": true,
"requires_passkeys": true,
"enable_pocketbase": true
}
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/stacks"
payload = {
"name": "<string>",
"stack_spec": {},
"user_config": {},
"user_config_raw": "<string>",
"provider": "<string>",
"services": ["<string>"],
"options": {
"enable_pocket_id": True,
"enable_pocketbase_backend": True,
"requires_passkeys": True,
"enable_pocketbase": 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({
name: '<string>',
stack_spec: {},
user_config: {},
user_config_raw: '<string>',
provider: '<string>',
services: ['<string>'],
options: {
enable_pocket_id: true,
enable_pocketbase_backend: true,
requires_passkeys: true,
enable_pocketbase: true
}
})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/stacks', 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",
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([
'name' => '<string>',
'stack_spec' => [
],
'user_config' => [
],
'user_config_raw' => '<string>',
'provider' => '<string>',
'services' => [
'<string>'
],
'options' => [
'enable_pocket_id' => true,
'enable_pocketbase_backend' => true,
'requires_passkeys' => true,
'enable_pocketbase' => 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"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\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")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/stacks")
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 \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"stack_id": "<string>",
"server_id": "<string>",
"job_id": "<string>",
"name": "<string>",
"state": "provisioning",
"message": "<string>",
"operations_url": "/stacks?stack_id=stack_123",
"idempotent_replay": true,
"bootstrap_token": "<string>",
"bootstrap_token_expires_at": "2023-11-07T05:31:56Z",
"owner_spec_endpoint": "/api/v1/stacks/stack_123/owner-spec",
"owner_spec_scopes": [
"read:owner-spec"
]
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}Create a StackKit deployment in the owner's Homelab
Creates an internal StackKit deployment under the authenticated B2C
owner’s singleton Homelab from the canonical StackKits stack-spec
payload supplied as stack_spec. The legacy /stacks route and
stack_id response field identify that deployment; they do not create
or select a second Homelab product. One TechStack instance can serve
many owners, each with their own Homelab. Legacy
user_config/kombination payloads remain accepted at this compatibility
boundary. Wizard clients should send a stable X-Idempotency-Key;
retries with the same key and payload return the original deployment,
planned server, and provisioning job.
curl --request POST \
--url https://api.kombify.io/v1/techstack/api/v1/stacks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"stack_spec": {},
"user_config": {},
"user_config_raw": "<string>",
"provider": "<string>",
"services": [
"<string>"
],
"options": {
"enable_pocket_id": true,
"enable_pocketbase_backend": true,
"requires_passkeys": true,
"enable_pocketbase": true
}
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/stacks"
payload = {
"name": "<string>",
"stack_spec": {},
"user_config": {},
"user_config_raw": "<string>",
"provider": "<string>",
"services": ["<string>"],
"options": {
"enable_pocket_id": True,
"enable_pocketbase_backend": True,
"requires_passkeys": True,
"enable_pocketbase": 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({
name: '<string>',
stack_spec: {},
user_config: {},
user_config_raw: '<string>',
provider: '<string>',
services: ['<string>'],
options: {
enable_pocket_id: true,
enable_pocketbase_backend: true,
requires_passkeys: true,
enable_pocketbase: true
}
})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/stacks', 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",
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([
'name' => '<string>',
'stack_spec' => [
],
'user_config' => [
],
'user_config_raw' => '<string>',
'provider' => '<string>',
'services' => [
'<string>'
],
'options' => [
'enable_pocket_id' => true,
'enable_pocketbase_backend' => true,
'requires_passkeys' => true,
'enable_pocketbase' => 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"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\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")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/stacks")
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 \"name\": \"<string>\",\n \"stack_spec\": {},\n \"user_config\": {},\n \"user_config_raw\": \"<string>\",\n \"provider\": \"<string>\",\n \"services\": [\n \"<string>\"\n ],\n \"options\": {\n \"enable_pocket_id\": true,\n \"enable_pocketbase_backend\": true,\n \"requires_passkeys\": true,\n \"enable_pocketbase\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"stack_id": "<string>",
"server_id": "<string>",
"job_id": "<string>",
"name": "<string>",
"state": "provisioning",
"message": "<string>",
"operations_url": "/stacks?stack_id=stack_123",
"idempotent_replay": true,
"bootstrap_token": "<string>",
"bootstrap_token_expires_at": "2023-11-07T05:31:56Z",
"owner_spec_endpoint": "/api/v1/stacks/stack_123/owner-spec",
"owner_spec_scopes": [
"read:owner-spec"
]
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}授权
OIDC/JWKS bearer token. Self-hosted defaults to Pocket ID; SaaS uses Auth0 through the edge. PocketBase JWT is legacy migration compatibility only.
请求头
Stable wizard-attempt key. Maximum 256 characters.
256请求体
Stack name
Wizard mode
easy, techie Canonical StackKits stack-spec.yaml shape generated by the creation wizard. When present, this is the source of truth for provisioning and is stored as the stack user_config for compatibility.
Legacy structured configuration, including older kombination-style payloads. New wizard clients should send stack_spec.
Raw YAML/JSON string
json, yaml Infrastructure provider (direct format)
Service names (direct format)
Show child attributes
Show child attributes
响应
StackKit deployment accepted
Canonical planned ServerRuntime created with the stack.
"provisioning"
Durable dashboard location for rollout, retry, diagnostics, and cleanup.
"/stacks?stack_id=stack_123"
True when the response reuses an earlier creation attempt.
Short-lived bearer token for the StackKit owner-spec bootstrap endpoint. Present when the create request includes local owner bootstrap material.
Expiration timestamp for bootstrap_token.
Stack-scoped endpoint consumed by StackKit admin-bootstrap.
"/api/v1/stacks/stack_123/owner-spec"
["read:owner-spec"]
