Config-as-code
The Management API lets you treat an entire chatbot's configuration as a single desired-state document. The workflow is GitOps-style:
GET /api/v1/chatbots/{id}/config → edit the document → POST /api/v1/chatbots/{id}/apply
You export the current config, change it (in code, in a file, in a PR), then apply the result. The server diffs your document against the live config and reconciles the difference.
1. Export the current config
curl https://www.wizchat.com/api/v1/chatbots/abc123/config \
-H "Authorization: Bearer $WIZCHAT_API_KEY"
The response is a canonical, re-appliable document:
{
"apiVersion": "wizchat/v1",
"kind": "ChatbotConfig",
"prune": true,
"spec": {
"chatbot": { "name": "Support Bot" },
"mcpServers": [ /* ... */ ],
"skills": [ /* ... */ ],
"domains": [ /* ... */ ]
}
}
getConfig requires chatbots:read plus the per-section read scopes. Sections
your key cannot read are reported in _omittedSections instead of spec.
2. Edit, then dry-run
Always preview changes first. Pass ?dryRun=true to compute the plan
without writing anything:
curl -X POST "https://www.wizchat.com/api/v1/chatbots/abc123/apply?dryRun=true" \
-H "Authorization: Bearer $WIZCHAT_API_KEY" \
-H "Content-Type: application/json" \
-d @config.json
A dry-run response is { "dryRun": true, "plan": [...] } — every create,
update, and delete the apply would perform.
3. Apply
Drop the query flag to execute:
curl -X POST "https://www.wizchat.com/api/v1/chatbots/abc123/apply" \
-H "Authorization: Bearer $WIZCHAT_API_KEY" \
-H "Content-Type: application/json" \
-d @config.json
On full success the response is:
{
"dryRun": false,
"plan": [ /* the executed plan */ ],
"applied": [ /* ops that ran */ ],
"failed": null,
"config": { /* refreshed config document */ }
}
Prune is on by default
The array sections (mcpServers, skills, domains) are authoritative.
With prune: true (the server default), any resource that exists on the
chatbot but is absent from your document is deleted. Every delete is
surfaced in the dry-run plan, so always dry-run before applying.
Set prune: false (on the document, or via the SDK option) for merge-only
behavior — creates and updates, never deletes.
Partial failure (422)
Apply stops on the first failing operation and returns 422 Unprocessable Entity with an ApplyResult whose failed field is populated and whose
applied lists the ops that succeeded before it. Apply is idempotent —
fix the offending section and re-run the same document.
{
"dryRun": false,
"applied": [ /* ops that succeeded */ ],
"failed": { "op": "...", "error": { "code": "...", "message": "..." } }
}
With the SDKs
applyConfig / apply_config return an ApplyResult for both full
success (200) and partial failure (422) — inspect failed rather than
catching an exception for the partial case. Auth and validation errors
(400/401/403/404/429) still throw.
TypeScript
import { createWizChatClient } from '@wizchat/management';
const wizchat = createWizChatClient({ apiKey: process.env.WIZCHAT_API_KEY! });
// 1. Export
const config = await wizchat.getConfig('abc123');
// 2. Edit
config.spec.chatbot.name = 'Renamed Bot';
// 3. Dry-run, then apply
const plan = await wizchat.applyConfig('abc123', config, { dryRun: true });
console.log(plan.plan);
const result = await wizchat.applyConfig('abc123', config);
if (result.failed) {
console.error('Partial failure:', result.failed);
} else {
console.log('Applied:', result.applied);
}
Python
import os
from wizchat_management import WizChatClient
with WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"]) as wizchat:
# 1. Export
config = wizchat.get_config("abc123")
# 2. Edit
config.spec.chatbot.name = "Renamed Bot"
# 3. Dry-run, then apply
plan = wizchat.apply_config("abc123", config, dry_run=True)
print(plan.plan)
result = wizchat.apply_config("abc123", config) # prune defaults to True
if result.failed:
print("Partial failure:", result.failed)
else:
print("Applied:", result.applied)
To keep the live config untouched for sections you don't manage, export with
getConfig, change only what you need, and re-apply the whole document — the
diff engine leaves unchanged sections alone.