# SDK Documentation\n\nThis document provides comprehensive documentation for the official SDKs and client libraries available for provisioning.\n\n## Available SDKs\n\nProvisioning provides SDKs in multiple languages to facilitate integration:\n\n### Official SDKs\n\n- **Python SDK** (`provisioning-client`) - Full-featured Python client\n- **JavaScript/TypeScript SDK** (`@provisioning/client`) - Node.js and browser support\n- **Go SDK** (`go-provisioning-client`) - Go client library\n- **Rust SDK** (`provisioning-rs`) - Native Rust integration\n\n### Community SDKs\n\n- **Java SDK** - Community-maintained Java client\n- **C# SDK** - .NET client library\n- **PHP SDK** - PHP client library\n\n## Python SDK\n\n### Installation\n\n```\n# Install from PyPI\npip install provisioning-client\n\n# Or install development version\npip install git+https://github.com/provisioning-systems/python-client.git\n```\n\n### Quick Start\n\n```\nfrom provisioning_client import ProvisioningClient\nimport asyncio\n\nasync def main():\n    # Initialize client\n    client = ProvisioningClient(\n        base_url="http://localhost:9090",\n        auth_url="http://localhost:8081",\n        username="admin",\n        password="your-password"\n    )\n\n    try:\n        # Authenticate\n        token = await client.authenticate()\n        print(f"Authenticated with token: {token[:20]}...")\n\n        # Create a server workflow\n        task_id = client.create_server_workflow(\n            infra="production",\n            settings="prod-settings.ncl",\n            wait=False\n        )\n        print(f"Server workflow created: {task_id}")\n\n        # Wait for completion\n        task = client.wait_for_task_completion(task_id, timeout=600)\n        print(f"Task completed with status: {task.status}")\n\n        if task.status == "Completed":\n            print(f"Output: {task.output}")\n        elif task.status == "Failed":\n            print(f"Error: {task.error}")\n\n    except Exception as e:\n        print(f"Error: {e}")\n\nif __name__ == "__main__":\n    asyncio.run(main())\n```\n\n### Advanced Usage\n\n#### WebSocket Integration\n\n```\nasync def monitor_workflows():\n    client = ProvisioningClient()\n    await client.authenticate()\n\n    # Set up event handlers\n    async def on_task_update(event):\n        print(f"Task {event['data']['task_id']} status: {event['data']['status']}")\n\n    async def on_progress_update(event):\n        print(f"Progress: {event['data']['progress']}% - {event['data']['current_step']}")\n\n    client.on_event('TaskStatusChanged', on_task_update)\n    client.on_event('WorkflowProgressUpdate', on_progress_update)\n\n    # Connect to WebSocket\n    await client.connect_websocket(['TaskStatusChanged', 'WorkflowProgressUpdate'])\n\n    # Keep connection alive\n    await asyncio.sleep(3600)  # Monitor for 1 hour\n```\n\n#### Batch Operations\n\n```\nasync def execute_batch_deployment():\n    client = ProvisioningClient()\n    await client.authenticate()\n\n    batch_config = {\n        "name": "production_deployment",\n        "version": "1.0.0",\n        "storage_backend": "surrealdb",\n        "parallel_limit": 5,\n        "rollback_enabled": True,\n        "operations": [\n            {\n                "id": "servers",\n                "type": "server_batch",\n                "provider": "upcloud",\n                "dependencies": [],\n                "config": {\n                    "server_configs": [\n                        {"name": "web-01", "plan": "2xCPU-4 GB", "zone": "de-fra1"},\n                        {"name": "web-02", "plan": "2xCPU-4 GB", "zone": "de-fra1"}\n                    ]\n                }\n            },\n            {\n                "id": "kubernetes",\n                "type": "taskserv_batch",\n                "provider": "upcloud",\n                "dependencies": ["servers"],\n                "config": {\n                    "taskservs": ["kubernetes", "cilium", "containerd"]\n                }\n            }\n        ]\n    }\n\n    # Execute batch operation\n    batch_result = await client.execute_batch_operation(batch_config)\n    print(f"Batch operation started: {batch_result['batch_id']}")\n\n    # Monitor progress\n    while True:\n        status = await client.get_batch_status(batch_result['batch_id'])\n        print(f"Batch status: {status['status']} - {status.get('progress', 0)}%")\n\n        if status['status'] in ['Completed', 'Failed', 'Cancelled']:\n            break\n\n        await asyncio.sleep(10)\n\n    print(f"Batch operation finished: {status['status']}")\n```\n\n#### Error Handling with Retries\n\n```\nfrom provisioning_client.exceptions import (\n    ProvisioningAPIError,\n    AuthenticationError,\n    ValidationError,\n    RateLimitError\n)\nfrom tenacity import retry, stop_after_attempt, wait_exponential\n\nclass RobustProvisioningClient(ProvisioningClient):\n    @retry(\n        stop=stop_after_attempt(3),\n        wait=wait_exponential(multiplier=1, min=4, max=10)\n    )\n    async def create_server_workflow_with_retry(self, **kwargs):\n        try:\n            return await self.create_server_workflow(**kwargs)\n        except RateLimitError as e:\n            print(f"Rate limited, retrying in {e.retry_after} seconds...")\n            await asyncio.sleep(e.retry_after)\n            raise\n        except AuthenticationError:\n            print("Authentication failed, re-authenticating...")\n            await self.authenticate()\n            raise\n        except ValidationError as e:\n            print(f"Validation error: {e}")\n            # Don't retry validation errors\n            raise\n        except ProvisioningAPIError as e:\n            print(f"API error: {e}")\n            raise\n\n# Usage\nasync def robust_workflow():\n    client = RobustProvisioningClient()\n\n    try:\n        task_id = await client.create_server_workflow_with_retry(\n            infra="production",\n            settings="config.ncl"\n        )\n        print(f"Workflow created successfully: {task_id}")\n    except Exception as e:\n        print(f"Failed after retries: {e}")\n```\n\n### API Reference\n\n#### ProvisioningClient Class\n\n```\nclass ProvisioningClient:\n    def __init__(self,\n                 base_url: str = "http://localhost:9090",\n                 auth_url: str = "http://localhost:8081",\n                 username: str = None,\n                 password: str = None,\n                 token: str = None):\n        """Initialize the provisioning client"""\n\n    async def authenticate(self) -> str:\n        """Authenticate and get JWT token"""\n\n    def create_server_workflow(self,\n                             infra: str,\n                             settings: str = "config.ncl",\n                             check_mode: bool = False,\n                             wait: bool = False) -> str:\n        """Create a server provisioning workflow"""\n\n    def create_taskserv_workflow(self,\n                               operation: str,\n                               taskserv: str,\n                               infra: str,\n                               settings: str = "config.ncl",\n                               check_mode: bool = False,\n                               wait: bool = False) -> str:\n        """Create a task service workflow"""\n\n    def get_task_status(self, task_id: str) -> WorkflowTask:\n        """Get the status of a specific task"""\n\n    def wait_for_task_completion(self,\n                               task_id: str,\n                               timeout: int = 300,\n                               poll_interval: int = 5) -> WorkflowTask:\n        """Wait for a task to complete"""\n\n    async def connect_websocket(self, event_types: List[str] = None):\n        """Connect to WebSocket for real-time updates"""\n\n    def on_event(self, event_type: str, handler: Callable):\n        """Register an event handler"""\n```\n\n## JavaScript/TypeScript SDK\n\n### Installation\n\n```\n# npm\nnpm install @provisioning/client\n\n# yarn\nyarn add @provisioning/client\n\n# pnpm\npnpm add @provisioning/client\n```\n\n### Quick Start\n\n```\nimport { ProvisioningClient } from '@provisioning/client';\n\nasync function main() {\n  const client = new ProvisioningClient({\n    baseUrl: 'http://localhost:9090',\n    authUrl: 'http://localhost:8081',\n    username: 'admin',\n    password: 'your-password'\n  });\n\n  try {\n    // Authenticate\n    await client.authenticate();\n    console.log('Authentication successful');\n\n    // Create server workflow\n    const taskId = await client.createServerWorkflow({\n      infra: 'production',\n      settings: 'prod-settings.ncl'\n    });\n    console.log(`Server workflow created: ${taskId}`);\n\n    // Wait for completion\n    const task = await client.waitForTaskCompletion(taskId);\n    console.log(`Task completed with status: ${task.status}`);\n\n  } catch (error) {\n    console.error('Error:', error.message);\n  }\n}\n\nmain();\n```\n\n### React Integration\n\n```\nimport React, { useState, useEffect } from 'react';\nimport { ProvisioningClient } from '@provisioning/client';\n\ninterface Task {\n  id: string;\n  name: string;\n  status: string;\n  progress?: number;\n}\n\nconst WorkflowDashboard: React.FC = () => {\n  const [client] = useState(() => new ProvisioningClient({\n    baseUrl: process.env.REACT_APP_API_URL,\n    username: process.env.REACT_APP_USERNAME,\n    password: process.env.REACT_APP_PASSWORD\n  }));\n\n  const [tasks, setTasks] = useState<Task[]>([]);\n  const [connected, setConnected] = useState(false);\n\n  useEffect(() => {\n    const initClient = async () => {\n      try {\n        await client.authenticate();\n\n        // Set up WebSocket event handlers\n        client.on('TaskStatusChanged', (event: any) => {\n          setTasks(prev => prev.map(task =>\n            task.id === event.data.task_id\n              ? { ...task, status: event.data.status, progress: event.data.progress }\n              : task\n          ));\n        });\n\n        client.on('websocketConnected', () => {\n          setConnected(true);\n        });\n\n        client.on('websocketDisconnected', () => {\n          setConnected(false);\n        });\n\n        // Connect WebSocket\n        await client.connectWebSocket(['TaskStatusChanged', 'WorkflowProgressUpdate']);\n\n        // Load initial tasks\n        const initialTasks = await client.listTasks();\n        setTasks(initialTasks);\n\n      } catch (error) {\n        console.error('Failed to initialize client:', error);\n      }\n    };\n\n    initClient();\n\n    return () => {\n      client.disconnectWebSocket();\n    };\n  }, [client]);\n\n  const createServerWorkflow = async () => {\n    try {\n      const taskId = await client.createServerWorkflow({\n        infra: 'production',\n        settings: 'config.ncl'\n      });\n\n      // Add to tasks list\n      setTasks(prev => [...prev, {\n        id: taskId,\n        name: 'Server Creation',\n        status: 'Pending'\n      }]);\n\n    } catch (error) {\n      console.error('Failed to create workflow:', error);\n    }\n  };\n\n  return (\n    <div className="workflow-dashboard">\n      <div className="header">\n        <h1>Workflow Dashboard</h1>\n        <div className={`connection-status ${connected ? 'connected' : 'disconnected'}`}>\n          {connected ? '🟢 Connected' : '🔴 Disconnected'}\n        </div>\n      </div>\n\n      <div className="controls">\n        <button onClick={createServerWorkflow}>\n          Create Server Workflow\n        </button>\n      </div>\n\n      <div className="tasks">\n        {tasks.map(task => (\n          <div key={task.id} className="task-card">\n            <h3>{task.name}</h3>\n            <div className="task-status">\n              <span className={`status ${task.status.toLowerCase()}`}>\n                {task.status}\n              </span>\n              {task.progress && (\n                <div className="progress-bar">\n                  <div\n                    className="progress-fill"\n                    style={{ width: `${task.progress}%` }}\n                  />\n                  <span className="progress-text">{task.progress}%</span>\n                </div>\n              )}\n            </div>\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n};\n\nexport default WorkflowDashboard;\n```\n\n### Node.js CLI Tool\n\n```\n#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { ProvisioningClient } from '@provisioning/client';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\nconst program = new Command();\n\nprogram\n  .name('provisioning-cli')\n  .description('CLI tool for provisioning')\n  .version('1.0.0');\n\nprogram\n  .command('create-server')\n  .description('Create a server workflow')\n  .requiredOption('-i, --infra <infra>', 'Infrastructure target')\n  .option('-s, --settings <settings>', 'Settings file', 'config.ncl')\n  .option('-c, --check', 'Check mode only')\n  .option('-w, --wait', 'Wait for completion')\n  .action(async (options) => {\n    const client = new ProvisioningClient({\n      baseUrl: process.env.PROVISIONING_API_URL,\n      username: process.env.PROVISIONING_USERNAME,\n      password: process.env.PROVISIONING_PASSWORD\n    });\n\n    const spinner = ora('Authenticating...').start();\n\n    try {\n      await client.authenticate();\n      spinner.text = 'Creating server workflow...';\n\n      const taskId = await client.createServerWorkflow({\n        infra: options.infra,\n        settings: options.settings,\n        check_mode: options.check,\n        wait: false\n      });\n\n      spinner.succeed(`Server workflow created: ${chalk.green(taskId)}`);\n\n      if (options.wait) {\n        spinner.start('Waiting for completion...');\n\n        // Set up progress updates\n        client.on('TaskStatusChanged', (event: any) => {\n          if (event.data.task_id === taskId) {\n            spinner.text = `Status: ${event.data.status}`;\n          }\n        });\n\n        client.on('WorkflowProgressUpdate', (event: any) => {\n          if (event.data.workflow_id === taskId) {\n            spinner.text = `${event.data.progress}% - ${event.data.current_step}`;\n          }\n        });\n\n        await client.connectWebSocket(['TaskStatusChanged', 'WorkflowProgressUpdate']);\n\n        const task = await client.waitForTaskCompletion(taskId);\n\n        if (task.status === 'Completed') {\n          spinner.succeed(chalk.green('Workflow completed successfully!'));\n          if (task.output) {\n            console.log(chalk.gray('Output:'), task.output);\n          }\n        } else {\n          spinner.fail(chalk.red(`Workflow failed: ${task.error}`));\n          process.exit(1);\n        }\n      }\n\n    } catch (error) {\n      spinner.fail(chalk.red(`Error: ${error.message}`));\n      process.exit(1);\n    }\n  });\n\nprogram\n  .command('list-tasks')\n  .description('List all tasks')\n  .option('-s, --status <status>', 'Filter by status')\n  .action(async (options) => {\n    const client = new ProvisioningClient();\n\n    try {\n      await client.authenticate();\n      const tasks = await client.listTasks(options.status);\n\n      console.log(chalk.bold('Tasks:'));\n      tasks.forEach(task => {\n        const statusColor = task.status === 'Completed' ? 'green' :\n                          task.status === 'Failed' ? 'red' :\n                          task.status === 'Running' ? 'yellow' : 'gray';\n\n        console.log(`  ${task.id} - ${task.name} [${chalk[statusColor](task.status)}]`);\n      });\n\n    } catch (error) {\n      console.error(chalk.red(`Error: ${error.message}`));\n      process.exit(1);\n    }\n  });\n\nprogram\n  .command('monitor')\n  .description('Monitor workflows in real-time')\n  .action(async () => {\n    const client = new ProvisioningClient();\n\n    try {\n      await client.authenticate();\n\n      console.log(chalk.bold('🔍 Monitoring workflows...'));\n      console.log(chalk.gray('Press Ctrl+C to stop'));\n\n      client.on('TaskStatusChanged', (event: any) => {\n        const timestamp = new Date().toLocaleTimeString();\n        const statusColor = event.data.status === 'Completed' ? 'green' :\n                          event.data.status === 'Failed' ? 'red' :\n                          event.data.status === 'Running' ? 'yellow' : 'gray';\n\n        console.log(`[${chalk.gray(timestamp)}] Task ${event.data.task_id} → ${chalk[statusColor](event.data.status)}`);\n      });\n\n      client.on('WorkflowProgressUpdate', (event: any) => {\n        const timestamp = new Date().toLocaleTimeString();\n        console.log(`[${chalk.gray(timestamp)}] ${event.data.workflow_id}: ${event.data.progress}% - ${event.data.current_step}`);\n      });\n\n      await client.connectWebSocket(['TaskStatusChanged', 'WorkflowProgressUpdate']);\n\n      // Keep the process running\n      process.on('SIGINT', () => {\n        console.log(chalk.yellow('\nStopping monitor...'));\n        client.disconnectWebSocket();\n        process.exit(0);\n      });\n\n      // Keep alive\n      setInterval(() => {}, 1000);\n\n    } catch (error) {\n      console.error(chalk.red(`Error: ${error.message}`));\n      process.exit(1);\n    }\n  });\n\nprogram.parse();\n```\n\n### API Reference\n\n```\ninterface ProvisioningClientOptions {\n  baseUrl?: string;\n  authUrl?: string;\n  username?: string;\n  password?: string;\n  token?: string;\n}\n\nclass ProvisioningClient extends EventEmitter {\n  constructor(options: ProvisioningClientOptions);\n\n  async authenticate(): Promise<string>;\n\n  async createServerWorkflow(config: {\n    infra: string;\n    settings?: string;\n    check_mode?: boolean;\n    wait?: boolean;\n  }): Promise<string>;\n\n  async createTaskservWorkflow(config: {\n    operation: string;\n    taskserv: string;\n    infra: string;\n    settings?: string;\n    check_mode?: boolean;\n    wait?: boolean;\n  }): Promise<string>;\n\n  async getTaskStatus(taskId: string): Promise<Task>;\n\n  async listTasks(statusFilter?: string): Promise<Task[]>;\n\n  async waitForTaskCompletion(\n    taskId: string,\n    timeout?: number,\n    pollInterval?: number\n  ): Promise<Task>;\n\n  async connectWebSocket(eventTypes?: string[]): Promise<void>;\n\n  disconnectWebSocket(): void;\n\n  async executeBatchOperation(batchConfig: BatchConfig): Promise<any>;\n\n  async getBatchStatus(batchId: string): Promise<any>;\n}\n```\n\n## Go SDK\n\n### Installation\n\n```\ngo get github.com/provisioning-systems/go-client\n```\n\n### Quick Start\n\n```\npackage main\n\nimport (\n    "context"\n    "fmt"\n    "log"\n    "time"\n\n    "github.com/provisioning-systems/go-client"\n)\n\nfunc main() {\n    // Initialize client\n    client, err := provisioning.NewClient(&provisioning.Config{\n        BaseURL:  "http://localhost:9090",\n        AuthURL:  "http://localhost:8081",\n        Username: "admin",\n        Password: "your-password",\n    })\n    if err != nil {\n        log.Fatalf("Failed to create client: %v", err)\n    }\n\n    ctx := context.Background()\n\n    // Authenticate\n    token, err := client.Authenticate(ctx)\n    if err != nil {\n        log.Fatalf("Authentication failed: %v", err)\n    }\n    fmt.Printf("Authenticated with token: %.20s...\n", token)\n\n    // Create server workflow\n    taskID, err := client.CreateServerWorkflow(ctx, &provisioning.CreateServerRequest{\n        Infra:    "production",\n        Settings: "prod-settings.ncl",\n        Wait:     false,\n    })\n    if err != nil {\n        log.Fatalf("Failed to create workflow: %v", err)\n    }\n    fmt.Printf("Server workflow created: %s\n", taskID)\n\n    // Wait for completion\n    task, err := client.WaitForTaskCompletion(ctx, taskID, 10*time.Minute)\n    if err != nil {\n        log.Fatalf("Failed to wait for completion: %v", err)\n    }\n\n    fmt.Printf("Task completed with status: %s\n", task.Status)\n    if task.Status == "Completed" {\n        fmt.Printf("Output: %s\n", task.Output)\n    } else if task.Status == "Failed" {\n        fmt.Printf("Error: %s\n", task.Error)\n    }\n}\n```\n\n### WebSocket Integration\n\n```\npackage main\n\nimport (\n    "context"\n    "fmt"\n    "log"\n    "os"\n    "os/signal"\n\n    "github.com/provisioning-systems/go-client"\n)\n\nfunc main() {\n    client, err := provisioning.NewClient(&provisioning.Config{\n        BaseURL:  "http://localhost:9090",\n        Username: "admin",\n        Password: "password",\n    })\n    if err != nil {\n        log.Fatalf("Failed to create client: %v", err)\n    }\n\n    ctx := context.Background()\n\n    // Authenticate\n    _, err = client.Authenticate(ctx)\n    if err != nil {\n        log.Fatalf("Authentication failed: %v", err)\n    }\n\n    // Set up WebSocket connection\n    ws, err := client.ConnectWebSocket(ctx, []string{\n        "TaskStatusChanged",\n        "WorkflowProgressUpdate",\n    })\n    if err != nil {\n        log.Fatalf("Failed to connect WebSocket: %v", err)\n    }\n    defer ws.Close()\n\n    // Handle events\n    go func() {\n        for event := range ws.Events() {\n            switch event.Type {\n            case "TaskStatusChanged":\n                fmt.Printf("Task %s status changed to: %s\n",\n                    event.Data["task_id"], event.Data["status"])\n            case "WorkflowProgressUpdate":\n                fmt.Printf("Workflow progress: %v%% - %s\n",\n                    event.Data["progress"], event.Data["current_step"])\n            }\n        }\n    }()\n\n    // Wait for interrupt\n    c := make(chan os.Signal, 1)\n    signal.Notify(c, os.Interrupt)\n    <-c\n\n    fmt.Println("Shutting down...")\n}\n```\n\n### HTTP Client with Retry Logic\n\n```\npackage main\n\nimport (\n    "context"\n    "fmt"\n    "time"\n\n    "github.com/provisioning-systems/go-client"\n    "github.com/cenkalti/backoff/v4"\n)\n\ntype ResilientClient struct {\n    *provisioning.Client\n}\n\nfunc NewResilientClient(config *provisioning.Config) (*ResilientClient, error) {\n    client, err := provisioning.NewClient(config)\n    if err != nil {\n        return nil, err\n    }\n\n    return &ResilientClient{Client: client}, nil\n}\n\nfunc (c *ResilientClient) CreateServerWorkflowWithRetry(\n    ctx context.Context,\n    req *provisioning.CreateServerRequest,\n) (string, error) {\n    var taskID string\n\n    operation := func() error {\n        var err error\n        taskID, err = c.CreateServerWorkflow(ctx, req)\n\n        // Don't retry validation errors\n        if provisioning.IsValidationError(err) {\n            return backoff.Permanent(err)\n        }\n\n        return err\n    }\n\n    exponentialBackoff := backoff.NewExponentialBackOff()\n    exponentialBackoff.MaxElapsedTime = 5 * time.Minute\n\n    err := backoff.Retry(operation, exponentialBackoff)\n    if err != nil {\n        return "", fmt.Errorf("failed after retries: %w", err)\n    }\n\n    return taskID, nil\n}\n\nfunc main() {\n    client, err := NewResilientClient(&provisioning.Config{\n        BaseURL:  "http://localhost:9090",\n        Username: "admin",\n        Password: "password",\n    })\n    if err != nil {\n        log.Fatalf("Failed to create client: %v", err)\n    }\n\n    ctx := context.Background()\n\n    // Authenticate with retry\n    _, err = client.Authenticate(ctx)\n    if err != nil {\n        log.Fatalf("Authentication failed: %v", err)\n    }\n\n    // Create workflow with retry\n    taskID, err := client.CreateServerWorkflowWithRetry(ctx, &provisioning.CreateServerRequest{\n        Infra:    "production",\n        Settings: "config.ncl",\n    })\n    if err != nil {\n        log.Fatalf("Failed to create workflow: %v", err)\n    }\n\n    fmt.Printf("Workflow created successfully: %s\n", taskID)\n}\n```\n\n## Rust SDK\n\n### Installation\n\nAdd to your `Cargo.toml`:\n\n```\n[dependencies]\nprovisioning-rs = "2.0.0"\ntokio = { version = "1.0", features = ["full"] }\n```\n\n### Quick Start\n\n```\nuse provisioning_rs::{ProvisioningClient, Config, CreateServerRequest};\nuse tokio;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    // Initialize client\n    let config = Config {\n        base_url: "http://localhost:9090".to_string(),\n        auth_url: Some("http://localhost:8081".to_string()),\n        username: Some("admin".to_string()),\n        password: Some("your-password".to_string()),\n        token: None,\n    };\n\n    let mut client = ProvisioningClient::new(config);\n\n    // Authenticate\n    let token = client.authenticate().await?;\n    println!("Authenticated with token: {}...", &token[..20]);\n\n    // Create server workflow\n    let request = CreateServerRequest {\n        infra: "production".to_string(),\n        settings: Some("prod-settings.ncl".to_string()),\n        check_mode: false,\n        wait: false,\n    };\n\n    let task_id = client.create_server_workflow(request).await?;\n    println!("Server workflow created: {}", task_id);\n\n    // Wait for completion\n    let task = client.wait_for_task_completion(&task_id, std::time::Duration::from_secs(600)).await?;\n\n    println!("Task completed with status: {:?}", task.status);\n    match task.status {\n        TaskStatus::Completed => {\n            if let Some(output) = task.output {\n                println!("Output: {}", output);\n            }\n        },\n        TaskStatus::Failed => {\n            if let Some(error) = task.error {\n                println!("Error: {}", error);\n            }\n        },\n        _ => {}\n    }\n\n    Ok(())\n}\n```\n\n### WebSocket Integration\n\n```\nuse provisioning_rs::{ProvisioningClient, Config, WebSocketEvent};\nuse futures_util::StreamExt;\nuse tokio;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let config = Config {\n        base_url: "http://localhost:9090".to_string(),\n        username: Some("admin".to_string()),\n        password: Some("password".to_string()),\n        ..Default::default()\n    };\n\n    let mut client = ProvisioningClient::new(config);\n\n    // Authenticate\n    client.authenticate().await?;\n\n    // Connect WebSocket\n    let mut ws = client.connect_websocket(vec![\n        "TaskStatusChanged".to_string(),\n        "WorkflowProgressUpdate".to_string(),\n    ]).await?;\n\n    // Handle events\n    tokio::spawn(async move {\n        while let Some(event) = ws.next().await {\n            match event {\n                Ok(WebSocketEvent::TaskStatusChanged { data }) => {\n                    println!("Task {} status changed to: {}", data.task_id, data.status);\n                },\n                Ok(WebSocketEvent::WorkflowProgressUpdate { data }) => {\n                    println!("Workflow progress: {}% - {}", data.progress, data.current_step);\n                },\n                Ok(WebSocketEvent::SystemHealthUpdate { data }) => {\n                    println!("System health: {}", data.overall_status);\n                },\n                Err(e) => {\n                    eprintln!("WebSocket error: {}", e);\n                    break;\n                }\n            }\n        }\n    });\n\n    // Keep the main thread alive\n    tokio::signal::ctrl_c().await?;\n    println!("Shutting down...");\n\n    Ok(())\n}\n```\n\n### Batch Operations\n\n```\nuse provisioning_rs::{BatchOperationRequest, BatchOperation};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = ProvisioningClient::new(config);\n    client.authenticate().await?;\n\n    // Define batch operation\n    let batch_request = BatchOperationRequest {\n        name: "production_deployment".to_string(),\n        version: "1.0.0".to_string(),\n        storage_backend: "surrealdb".to_string(),\n        parallel_limit: 5,\n        rollback_enabled: true,\n        operations: vec![\n            BatchOperation {\n                id: "servers".to_string(),\n                operation_type: "server_batch".to_string(),\n                provider: "upcloud".to_string(),\n                dependencies: vec![],\n                config: serde_json::json!({\n                    "server_configs": [\n                        {"name": "web-01", "plan": "2xCPU-4 GB", "zone": "de-fra1"},\n                        {"name": "web-02", "plan": "2xCPU-4 GB", "zone": "de-fra1"}\n                    ]\n                }),\n            },\n            BatchOperation {\n                id: "kubernetes".to_string(),\n                operation_type: "taskserv_batch".to_string(),\n                provider: "upcloud".to_string(),\n                dependencies: vec!["servers".to_string()],\n                config: serde_json::json!({\n                    "taskservs": ["kubernetes", "cilium", "containerd"]\n                }),\n            },\n        ],\n    };\n\n    // Execute batch operation\n    let batch_result = client.execute_batch_operation(batch_request).await?;\n    println!("Batch operation started: {}", batch_result.batch_id);\n\n    // Monitor progress\n    loop {\n        let status = client.get_batch_status(&batch_result.batch_id).await?;\n        println!("Batch status: {} - {}%", status.status, status.progress.unwrap_or(0.0));\n\n        match status.status.as_str() {\n            "Completed" | "Failed" | "Cancelled" => break,\n            _ => tokio::time::sleep(std::time::Duration::from_secs(10)).await,\n        }\n    }\n\n    Ok(())\n}\n```\n\n## Best Practices\n\n### Authentication and Security\n\n1. **Token Management**: Store tokens securely and implement automatic refresh\n2. **Environment Variables**: Use environment variables for credentials\n3. **HTTPS**: Always use HTTPS in production environments\n4. **Token Expiration**: Handle token expiration gracefully\n\n### Error Handling\n\n1. **Specific Exceptions**: Handle specific error types appropriately\n2. **Retry Logic**: Implement exponential backoff for transient failures\n3. **Circuit Breakers**: Use circuit breakers for resilient integrations\n4. **Logging**: Log errors with appropriate context\n\n### Performance Optimization\n\n1. **Connection Pooling**: Reuse HTTP connections\n2. **Async Operations**: Use asynchronous operations where possible\n3. **Batch Operations**: Group related operations for efficiency\n4. **Caching**: Cache frequently accessed data appropriately\n\n### WebSocket Connections\n\n1. **Reconnection**: Implement automatic reconnection with backoff\n2. **Event Filtering**: Subscribe only to needed event types\n3. **Error Handling**: Handle WebSocket errors gracefully\n4. **Resource Cleanup**: Properly close WebSocket connections\n\n### Testing\n\n1. **Unit Tests**: Test SDK functionality with mocked responses\n2. **Integration Tests**: Test against real API endpoints\n3. **Error Scenarios**: Test error handling paths\n4. **Load Testing**: Validate performance under load\n\nThis comprehensive SDK documentation provides developers with everything needed to integrate with provisioning using their preferred programming\nlanguage, complete with examples, best practices, and detailed API references.
