{"openapi": "3.1.0", "info": {"title": "Servera Developers API", "description": "A REST API for your Servera account - the same operations you have in the customer\narea, available programmatically, plus an **MCP** endpoint so AI agents can use\nthem as tools. Every request is authenticated with a scoped API key and rate-limited.\n\n### What you can do\nEverything from your customer area, grouped by area (each needs the matching scope):\n\n- **VPS / VDS** - list servers; live status + CPU/RAM/disk/network metrics; power\n  on/off/reboot; snapshots (create, roll back, delete); backups (create, delete);\n  the per-VM firewall (view, enable/disable, rules add/update/delete/reorder - on\n  standalone and behind-Virtual-Router VMs); and OS reinstall.\n- **VPC Networks** - list your private networks and manage their firewall (rules,\n  options, VM\u2194VM isolation toggle).\n- **Virtual Routers** - overview, WireGuard peers, public-IP mappings, and\n  attach/detach VMs behind the router.\n- **Domains & DNS** - list domains (nameservers, lock, DNSSEC, expiry) and read or\n  edit DNS records (A, AAAA, CNAME, MX, TXT, SRV, CAA) on both PowerDNS and\n  cPanel/WHM zones.\n- **WAF** - list protected domains, enable/disable protection, toggle threat\n  filtering, apply security presets, advanced rules, bot policy, IP/country\n  allow-block lists, and read traffic logs.\n- **Email - delivery & protection** - delivery trace, RBL/blocklist checks, the\n  RBL self-whitelist, trusted senders, and autoresponders.\n- **Billing** - list invoices, download their PDFs, and check your account balance.\n- **Orders** - list and inspect your orders.\n- **Support** - read tickets, open new ones, and post replies.\n- **IP protection** - check whether an IP is blocked on shared hosting, self-unblock\n  it, and view the history.\n- **Users** - list account users, invite new ones, and resend invitations.\n- **Contacts** - list and manage your account contacts.\n- **Tags & comments** - organise your services and domains with tags (a predefined\n  grouped catalog of international labels, or your own custom text) and a free-text\n  comment on each; find services/domains by tag. Scopes `tags:read`/`tags:write`.\n- **System emails** - the transactional emails we've sent to your account.\n- **Activity log** - your account's audited actions.\n\n## Base URL\n```\nhttps://developers.servera.lt\n```\nEvery `servera.*` brand has its own host (e.g. `https://developers.servera.co.uk`);\nthey share this API.\n\n## Quick start\n```bash\n# Public - no auth\ncurl https://developers.servera.lt/v1/status\n\n# Authenticated - list your VPS/VDS\ncurl https://developers.servera.lt/v1/vps \\\n  -H \"Authorization: Bearer sk_live_\u2026\"\n```\n\n## Authentication\nCreate a scoped API key in your customer area (**Developers \u2192 API keys**), then\nsend it as a bearer token on every request:\n```\nAuthorization: Bearer sk_live_\u2026\n```\nKeys are shown **once** at creation (only a hashed form is stored) and can be\nrevoked anytime. Send keys over HTTPS only, in the header - never in a URL.\n\n**Scopes** (a key with *no* scopes has full access to your own resources):\n\n| Scope | Grants |\n|-------|--------|\n| `vps:read` | List VPS/VDS, status, metrics, snapshots/backups/firewall/templates (read) |\n| `vps:power` | Start, stop, shutdown, reboot |\n| `vps:snapshots` | Create, roll back, delete snapshots |\n| `vps:backups` | Create, delete backups |\n| `vps:firewall` | Manage the firewall (enable/disable, rules) |\n| `vps:reinstall` | Reinstall the OS (**destructive**) |\n| `billing:read` | View invoices, PDFs, account balance |\n| `orders:read` | View orders |\n| `domains:read` | View domains, DNS records and contact email-verification status |\n| `domains:write` | Resend a domain's contact email-verification message |\n| `tickets:read` | View support tickets |\n| `dns:write` | Create, update, delete DNS records |\n| `tickets:write` | Open tickets and post replies |\n| `users:read` / `users:write` | View / invite account users |\n| `emails:read` | View system email history |\n| `security:read` / `security:write` | Check / unblock shared-hosting IP blocks |\n| `networks:read` / `networks:write` | View / manage VPC network firewall |\n| `vr:read` / `vr:write` | View / manage Virtual Routers |\n| `waf:read` / `waf:write` | View / manage the WAF |\n| `contacts:read` / `contacts:write` | View / manage account contacts |\n| `logs:read` | View your account activity log |\n| `ssl:read` | Preflight, list certificates, check issuance budget |\n| `ssl:write` | Issue, continue, and revoke certificates |\n| `tags:read` | List the tag catalog, read tags/comment, find entities by tag |\n| `tags:write` | Set tags and the comment on a service or domain |\n\n## Rate limiting\nRequests are limited **per API key** to **240 requests per minute** (fixed\n1-minute window). Every authenticated response carries the current budget:\n\n| Header | Meaning |\n|--------|---------|\n| `X-RateLimit-Limit` | Requests allowed per minute |\n| `X-RateLimit-Remaining` | Remaining in the current window |\n| `X-RateLimit-Reset` | Seconds until the window resets |\n\nExceeding the limit returns **`429 Too Many Requests`** with a `Retry-After`\nheader (seconds). Back off until then. The same limit applies to the MCP endpoint.\n\n## Errors\nStandard HTTP status codes. Error bodies are JSON with a `detail` field:\n```json\n{ \"detail\": \"service_suspended\" }\n```\n| Status | Meaning |\n|--------|---------|\n| `400` | Bad request (e.g. invalid action, `confirmation_required`) |\n| `401` | Missing/invalid/expired/revoked API key |\n| `403` | Key lacks the required scope, or the feature isn't enabled for you |\n| `404` | Resource not found or not owned by your account |\n| `409` | Conflict (e.g. VM locked by another operation) |\n| `429` | Rate limit exceeded - see `Retry-After` |\n| `5xx` | Server / hypervisor error - safe to retry with backoff |\n\n## Parameters & responses\nPath parameters (e.g. `service_id`) identify the resource; request bodies are\nJSON. Timestamps are ISO-8601 UTC. A field may be `null` when it is genuinely\nnot-applicable (e.g. `lock` when the VM isn't locked, `uptime_seconds` when it's\nstopped) - a `null` field is expected, never a bare `null` response body.\n\n## Pagination\nThe larger lists - `GET /v1/invoices`, `/v1/orders`, `/v1/tickets` - accept\n`limit` (1-200, default 50) and `offset`, and return a `total` count alongside the\nrows. Naturally small lists (`/v1/vps`, `/v1/domains`, snapshots, backups, DNS\nrecords) return the complete set for your account and take no pagination params.\n\n## For AI agents (MCP)\nAn **MCP** (Model Context Protocol) endpoint lets assistants like Claude call the\nsame operations as tools:\n```\nPOST https://developers.servera.lt/mcp\nAuthorization: Bearer sk_live_\u2026\n```\nIt speaks the Streamable-HTTP transport (JSON-RPC 2.0), authenticates with the\nsame API key, and enforces the same scopes. Tools carry safety annotations\n(read-only vs destructive) and structured output; your VPS fleet is also exposed\nas MCP **resources** (`servera:vps`, `servera:vps/{id}`).\n\n## Changelog\n- **v1.7** - **SSL** certificates (managed Let's Encrypt). Preflight auto-detects the\n  validation method (hosting AutoSSL, DNS-01, edge, or delegated/HTTP-01 fallback),\n  reports wildcard support and your weekly issuance budget. New scopes `ssl:read`/`ssl:write`.\n- **v1.6** - **WAF** (domains, enable/disable, threat-filter toggle, security presets,\n  advanced rules, bot policy, IP/country lists, traffic logs), account **Contacts**\n  (CRUD), and the account activity **Log**. New scopes `waf:read`/`write`,\n  `contacts:read`/`write`, `logs:read`. 22-language UI translations shipped.\n- **v1.5** - **Email delivery & protection**: delivery trace, RBL checks, whitelist,\n  trusted senders, autoresponders. Scopes `mail:read`/`mail:write`.\n- **v1.4** - **VPC networks** (list + firewall rules/options/internal-traffic) and\n  **Virtual Routers** (WireGuard peers, public-IP mappings, attach/detach VMs), plus\n  VPS firewall **rule edit/reorder**. New scopes `networks:read`/`write`, `vr:read`/`write`.\n- **v1.3** - Account **users** (list, invite, resend), **system email history**, and\n  shared-hosting **IP protection** (check / unblock / history). New scopes\n  `users:read`/`users:write`, `emails:read`, `security:read`/`security:write`. Same tools in MCP.\n- **v1.2** - Write actions: open/reply to support tickets (`tickets:write`) and\n  create/update/delete DNS records (`dns:write`) on both PowerDNS and cPanel/WHM\n  zones. Same tools in MCP.\n- **v1.1** - Read access to invoices (+PDF), account balance, orders, domains &\n  DNS records, and support tickets. New scopes: `billing:read`, `orders:read`,\n  `domains:read`, `tickets:read`. Same tools added to MCP.\n- **v1.0** - VPS/VDS: status, metrics, power, snapshots, backups, firewall, OS\n  reinstall; API keys with scopes; MCP endpoint; per-key rate limiting.\n\n## Support\nQuestions or a higher rate limit? Contact **info@servera.lt** or open a ticket in\nyour customer area.\n\n_This reference always reflects the live API - new endpoints appear here\nautomatically as they ship._\n", "version": "1.0.0"}, "servers": [{"url": "https://developers.servera.pt", "description": "Production"}], "paths": {"/v1/status": {"get": {"tags": ["Meta"], "summary": "API status", "description": "Liveness + version of the Developers API. No authentication required.", "operationId": "get_status", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"name": "Servera Developers API", "version": "1.0.0", "status": "ok", "docs": "https://developers.servera.lt"}}}}}}}, "/v1/me": {"get": {"tags": ["Meta"], "summary": "Who am I", "description": "Return the account this API key authenticates as. Handy for verifying a key.", "operationId": "get_me", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"customer_id": 4102, "email": "you@example.com", "name": "Jane Doe"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/vps": {"get": {"tags": ["VPS"], "summary": "List your VPS/VDS", "description": "List every VPS/VDS on your account (Proxmox virtual machines you own).", "operationId": "list_vps", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/VpsSummary"}, "type": "array", "title": "Response List Vps"}, "example": [{"id": 14684, "label": "web1.example.com", "status": "active", "product_type": "VDS", "ip_addresses": ["185.209.138.106"], "next_due_date": "2030-11-05"}]}}}}, "security": [{"ApiKey": []}]}}, "/v1/vps/{service_id}": {"get": {"tags": ["VPS"], "summary": "Get VPS status", "description": "Live power state + resource usage for one VPS/VDS you own, from the hypervisor.", "operationId": "get_vps", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 14684, "status": "running", "uptime_seconds": 1202479, "cpus": 8, "cpu": 0.0114, "mem_bytes": 10304565248, "maxmem_bytes": 17179869184, "disk_bytes": 0, "maxdisk_bytes": 64424509440, "locked": false}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/power": {"post": {"tags": ["VPS"], "summary": "Power action", "description": "Start, stop (force), shutdown (ACPI), or reboot a VPS/VDS you own.\n\nFor QEMU VMs `reboot` performs a hard reset (cloud images ship without the\nguest agent an ACPI reboot needs).", "operationId": "vps_power", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PowerRequest"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "action": "reboot"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/metrics": {"get": {"tags": ["VPS"], "summary": "VPS metrics (time series)", "description": "RRD time-series (cpu, memory, network, disk) for charts.\n`timeframe`: hour | day | week | month | year.", "operationId": "get_vps_metrics", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "timeframe", "in": "query", "required": false, "schema": {"type": "string", "default": "hour", "title": "Timeframe"}, "description": "Metrics window: `hour`, `day`, `week`, `month`, or `year`."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"series": [{"time": 1787052600, "cpu": 0.011, "mem": 10304565248, "maxmem": 17179869184, "netin": 1234.5, "netout": 217.2, "diskread": 0, "diskwrite": 1399.4}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/snapshots": {"get": {"tags": ["VPS"], "summary": "List snapshots", "description": "List snapshots for a VPS/VDS you own, with the snapshot quota.", "operationId": "list_snapshots", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"snapshots": [{"name": "before-upgrade", "description": "pre-upgrade", "snaptime": 1787000000, "vmstate": 0}], "max_snapshots": 7, "count": 1}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["VPS"], "summary": "Create snapshot", "description": "Create a snapshot (subject to your snapshot quota). `vmstate` includes RAM (QEMU only).", "operationId": "create_snapshot", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SnapshotCreate"}, "example": {"name": "before-upgrade", "description": "pre-upgrade snapshot", "vmstate": false}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/snapshots/{snapname}": {"delete": {"tags": ["VPS"], "summary": "Delete snapshot", "operationId": "delete_snapshot", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "snapname", "in": "path", "required": true, "schema": {"type": "string", "title": "Snapname"}, "description": "Snapshot name (from GET \u2026/snapshots)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Delete a snapshot by name from a VPS/VDS you own."}}, "/v1/vps/{service_id}/snapshots/{snapname}/rollback": {"post": {"tags": ["VPS"], "summary": "Roll back to snapshot", "description": "Restore the VM to a snapshot. This reverts disk (and RAM if the snapshot has it).", "operationId": "rollback_snapshot", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "snapname", "in": "path", "required": true, "schema": {"type": "string", "title": "Snapname"}, "description": "Snapshot name (from GET \u2026/snapshots)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/backups": {"get": {"tags": ["VPS"], "summary": "List backups", "description": "List backup dumps for a VPS/VDS you own.", "operationId": "list_backups", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"backups": [{"id": 1786483045, "created_at": "2026-08-11T21:17:25Z", "size_bytes": 21474836480, "notes": "web1.example.com", "protected": false, "verified": true}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["VPS"], "summary": "Create backup", "description": "Start a backup using your configured storage, retention and compression.", "operationId": "create_backup", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BackupCreate"}, "example": {"mode": "snapshot", "notes": "manual backup"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/backups/{backup_id}": {"delete": {"tags": ["VPS"], "summary": "Delete backup", "description": "Delete a backup by its `id` (from the backups list).", "operationId": "delete_backup", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "backup_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Backup Id"}, "description": "Backup id (from GET \u2026/backups)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/firewall": {"get": {"tags": ["VPS"], "summary": "Get firewall", "description": "Firewall state + rules. `managed_on` is `host` (Proxmox VM firewall) or\n`virtual_router` when the VPS sits behind a Virtual Router (single-layer).", "operationId": "get_firewall", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"enabled": true, "options": {"policy_in": "DROP", "policy_out": "ACCEPT", "enable": 1}, "rules": [{"pos": 0, "type": "in", "action": "ACCEPT", "proto": "tcp", "dport": "443", "enable": 1}], "ipv6_blocked": false, "managed_on": "host"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["VPS"], "summary": "Enable/disable firewall", "operationId": "set_firewall", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FirewallToggle"}, "example": {"enabled": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "enabled": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Turn the VPS/VDS firewall on or off."}}, "/v1/vps/{service_id}/firewall/rules": {"post": {"tags": ["VPS"], "summary": "Add firewall rule", "description": "Add a firewall rule. `type` is `in` (inbound) or `out` (outbound).", "operationId": "add_firewall_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FirewallRule"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/firewall/rules/{pos}": {"delete": {"tags": ["VPS"], "summary": "Delete firewall rule", "description": "Delete the firewall rule at position `pos` (as returned by GET /firewall).", "operationId": "delete_firewall_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["VPS"], "summary": "Update firewall rule", "description": "Update the firewall rule at `pos`. Empty fields clear that attribute on the rule.", "operationId": "update_firewall_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FirewallRule"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/os-templates": {"get": {"tags": ["VPS"], "summary": "List OS templates", "description": "The OS images you can reinstall this VPS/VDS with (respects per-service access).\n\nEach item has an `id` and a human `label` - pick the one you want and pass its\n`id` to `POST /reinstall` as `template_id`. `type` is the machine's\nvirtualization type (`qemu` or `lxc`); the list is already filtered to what's\ninstallable on it.", "operationId": "list_os_templates", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OsTemplateList"}, "example": {"type": "qemu", "templates": [{"id": 101, "label": "AlmaLinux 8", "os_family": "linux", "icon_url": "/uploads/option-icons/value-21.svg"}, {"id": 102, "label": "AlmaLinux 9", "os_family": "linux", "icon_url": null}, {"id": 118, "label": "Ubuntu 24.04", "os_family": "linux", "icon_url": null}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/reinstall": {"post": {"tags": ["VPS"], "summary": "Reinstall OS (destructive)", "description": "\u26a0\ufe0f Wipe the VPS/VDS and reinstall the chosen OS. **Irreversible - all data is lost.**\nRequires `confirm: true`. Runs asynchronously; poll `GET /reinstall-status`.", "operationId": "reinstall_os", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ReinstallRequest"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "message": "OS reinstall queued", "template": "AlmaLinux 9"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/reinstall-status": {"get": {"tags": ["VPS"], "summary": "Reinstall status", "description": "Progress of the most recent reinstall (poll while `reinstalling` is true).", "operationId": "reinstall_status", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"reinstalling": true, "status": "processing", "created_at": "2026-08-19T10:00:00+00:00", "started_at": "2026-08-19T10:00:05+00:00", "completed_at": null, "error": null}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/terminate": {"post": {"tags": ["VPS"], "summary": "Terminate/cancel a service (destructive)", "description": "\u26a0\ufe0f Terminate/cancel one of your services. **Destructive.** Uses the SAME flow as the\ncustomer panel - VM destroy + **IP release** + refund handling.\n\n`mode=immediate` destroys now (backgrounded); `mode=end_of_period` cancels at the end\nof the paid period (VM keeps running until then); `mode=scheduled` terminates on\n`scheduled_date` (YYYY-MM-DD). Requires `confirm: true`. An `Idempotency-Key` header is\nrequired. A service already terminated/cancelled or with a pending termination returns\nan error rather than acting twice.", "operationId": "terminate_service", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TerminateBody"}, "example": {"mode": "end_of_period", "confirm": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"has_pending_termination": true, "termination": {"id": 62, "termination_type": "end_of_period", "scheduled_date": "2026-09-26", "reason": "API/MCP termination", "status": "pending", "requested_by_name": "Jane Doe", "created_at": "2026-08-26T12:00:00Z"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/invoices": {"get": {"tags": ["Billing"], "summary": "List invoices", "description": "List your invoices (newest first). Optional `status` filter; paginated.", "operationId": "list_invoices", "security": [{"ApiKey": []}], "parameters": [{"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}, "description": "Filter by status."}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}, "description": "Row offset for pagination (default 0)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"invoices": [{"id": 103302, "number": "SRV-2026-000123", "status": "paid", "subtotal": 25.0, "tax": 5.25, "total": 30.25, "currency": "EUR", "date": "2026-08-01", "due_date": "2026-08-15", "paid_date": "2026-08-02", "type": "invoice", "public_hash": "a1b2c3"}], "total": 180, "limit": 50, "offset": 0}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/invoices/{invoice_id}": {"get": {"tags": ["Billing"], "summary": "Get invoice", "description": "One invoice with its line items.", "operationId": "get_invoice", "security": [{"ApiKey": []}], "parameters": [{"name": "invoice_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Invoice Id"}, "description": "Invoice id (from GET /invoices)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 103302, "number": "SRV-2026-000123", "status": "paid", "subtotal": 25.0, "tax": 5.25, "total": 30.25, "currency": "EUR", "currency_symbol": "\u20ac", "date": "2026-08-01", "due_date": "2026-08-15", "paid_date": "2026-08-02", "type": "invoice", "public_hash": "a1b2c3", "tax_rate": 21.0, "credit_applied": 0.0, "notes": null, "items": [{"id": 1, "type": "service_renewal", "description": "VDS Starter \u2014 renewal", "quantity": 1.0, "unit_price": 25.0, "amount": 25.0, "taxed": true}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/invoices/{invoice_id}/pdf": {"get": {"tags": ["Billing"], "summary": "Invoice PDF", "description": "Returns a **302 redirect** whose `Location` header points at the invoice's\nPDF. Follow the redirect to download it (most HTTP clients do automatically).", "operationId": "get_invoice_pdf", "security": [{"ApiKey": []}], "parameters": [{"name": "invoice_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Invoice Id"}, "description": "Invoice id (from GET /invoices)."}], "responses": {"302": {"description": "Redirect (Location header) to the rendered PDF file.", "content": {"application/json": {"schema": {}}}}, "404": {"description": "Invoice not found, or no PDF available yet."}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/billing/balance": {"get": {"tags": ["Billing"], "summary": "Account balance", "description": "Your account credit balance.", "operationId": "get_balance", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"credit": 24.58, "currency": "EUR", "symbol": "\u20ac"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/orders": {"get": {"tags": ["Orders"], "summary": "List orders", "description": "List your orders (newest first). Optional `status` filter; paginated.", "operationId": "list_orders", "security": [{"ApiKey": []}], "parameters": [{"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}, "description": "Filter by status."}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}, "description": "Row offset for pagination (default 0)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"orders": [{"id": 555, "number": "ORD-2026-000555", "status": "active", "subtotal": 25.0, "tax": 5.25, "total": 30.25, "currency": "EUR", "payment_method": "stripe", "item_count": 1, "invoice_number": "SRV-2026-000123", "invoice_hash": "a1b2c3", "created_at": "2026-08-01T10:00:00+00:00"}], "total": 147, "limit": 50, "offset": 0}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["Orders"], "summary": "Place an order (pending + proforma)", "description": "Place an order for one or more catalog items.\n\nCreates a **PENDING** order and an **UNPAID proforma** invoice - it does NOT charge\nor provision anything on its own. Pay it with `POST /invoices/{invoice_id}/pay`\n(from account credit) or via the returned `pay_url`. Uses the exact same cart +\ncheckout engine as the web panel.\n\nAn **`Idempotency-Key`** header is REQUIRED - a retry with the same key returns the\noriginal result instead of creating a duplicate order.\n\nReturns: `order_number`, `status` (`pending`), the amount breakdown\n(`net` = be PVM, `vat`, `vat_rate` %, `gross` = su PVM; `total` = `gross`), and an\n`invoice` object with `id`, `invoice_number` (the proforma number), `document_type`\n(`proforma`), the same net/vat/gross, `pay_url` and `pay_via_api`.", "operationId": "create_order", "security": [{"ApiKey": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OrderCreateBody"}, "example": {"items": [{"type": "product", "product_id": 2629, "billing_cycle": "monthly", "config_options": {"3": {"value_id": 71}}, "hostname": "app.example.com", "datacenter": "lt"}]}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"order_number": "ORD-202608-01979", "order_id": 7192, "status": "pending", "is_paid": false, "total": 7.85, "net": 6.49, "vat": 1.36, "vat_rate": 21.0, "gross": 7.85, "currency": "EUR", "invoice": {"id": 103361, "invoice_number": "SRD4026", "document_type": "proforma", "net": 6.49, "vat": 1.36, "vat_rate": 21.0, "gross": 7.85, "public_hash": "MmS69oAZ05d0I4L3RX6CRw3rChoki1M5", "pay_url": "https://servera.lt/saskaita/MmS69oAZ05d0I4L3RX6CRw3rChoki1M5", "pay_via_api": "POST /v1/invoices/103361/pay"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/orders/{order_id}": {"get": {"tags": ["Orders"], "summary": "Get order", "description": "One order with its domain and product line items.", "operationId": "get_order", "security": [{"ApiKey": []}], "parameters": [{"name": "order_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Order Id"}, "description": "Order id (from GET /orders)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 555, "number": "ORD-2026-000555", "status": "active", "subtotal": 25.0, "tax": 5.25, "total": 30.25, "currency": "EUR", "payment_method": "stripe", "promo_code": null, "promo_discount": 0.0, "invoice_number": "SRV-2026-000123", "invoice_hash": "a1b2c3", "created_at": "2026-08-01T10:00:00+00:00", "domains": [{"id": 1, "domain": "example.com", "type": "registration", "period": 1, "price": 9.99, "tld": "com"}], "products": [{"id": 1, "description": "VDS Starter", "product": "VDS Starter", "billing_cycle": "monthly", "quantity": 1, "amount": 25.0}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/products": {"get": {"tags": ["Catalog"], "summary": "List orderable products", "description": "Products you can order on your account (exactly what the panel shows - same site,\ncurrency and visibility rules). Each item has `product_id`, `name`, `module`, per-cycle\n`prices`, and `needs_os_template`. Pass a `product_id` + `billing_cycle` to POST /orders;\nfor configurable options (OS template, disk, extra IPs, ...) call\nGET /products/{product_id}/options.", "operationId": "list_products", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"products": [{"product_id": 2629, "name": "Linux VPS 1", "module": "vps", "needs_os_template": true, "prices": {"monthly": 6.49, "quarterly": 17.51, "semiannually": 33.08, "annually": 58.38, "biennially": 101.2, "triennially": 140.12}, "list_prices": {"annually": 77.84}, "discount": {"id": 17, "name": "Linux VDS/VPS First-Year Discount", "type": "percentage"}}, {"product_id": 2633, "name": "H1", "module": "cpanel", "needs_os_template": false, "prices": {"monthly": 9.09, "annually": 109.08}}], "currency": "EUR", "customer_id": 4102}}}}}, "security": [{"ApiKey": []}]}}, "/v1/products/{product_id}/options": {"get": {"tags": ["Catalog"], "summary": "Product configurable options", "description": "All configurable options for a product (OS templates, disk, RAM, extra IPv4/IPv6,\nbackups, ...) with each option's values, `value_id`s and prices - the same options the\npanel offers. Put the chosen `{ \"<option_id>\": { \"value_id\": <id> } }` into an order\nitem's `config_options` when calling POST /orders.", "operationId": "get_product_options", "security": [{"ApiKey": []}], "parameters": [{"name": "product_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Product Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"options": [{"option_id": 3, "name": "Operacin\u0117 sistema", "group": "Operacin\u0117 sistema", "category": "os_template", "required": true, "values": [{"value_id": 71, "name": "AlmaLinux 9 64bit", "pricing": {}}, {"value_id": 69, "name": "Debian 12 64bit", "pricing": {}}]}, {"option_id": 1, "name": "Atsargini\u0173 kopij\u0173 limitas", "group": "Serverio atsargin\u0117s kopijos", "category": "backup", "required": false, "values": [{"value_id": 15, "name": "vnt", "pricing": {"monthly": 1.99, "annually": 23.88}}]}, {"option_id": 4, "name": "IPv4 adresai", "group": "IP adresai", "category": "ipv4", "required": false, "values": [{"value_id": 17, "name": "1 papildomas IPv4", "pricing": {"monthly": 2.0}}]}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/provision": {"post": {"tags": ["Partner Provisioning"], "summary": "Create a customer and place an order", "description": "Create (or identify) an end customer and place a **PENDING** order with an\n**UNPAID proforma** invoice, in a single call, for partner-allowed products only.\n\nDoes not charge or provision anything on its own \u2014 the invoice is settled by the\nend customer via the returned `pay_url` (or bank transfer), and everything after\n(invoicing, payment reconciliation, renewals) is handled automatically.\n\nAn **`Idempotency-Key`** header is REQUIRED \u2014 send your own order id; a retry with\nthe same key returns the original result instead of creating a duplicate.\n\nReturns `customer_id`, `customer_created`, `order_number`, `status` (`pending`),\n`invoice_id`, `invoice_number` (the proforma), `total`, `currency` and `pay_url`.", "operationId": "partner_provision", "security": [{"ApiKey": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerProvisionBody"}, "example": {"customer": {"email": "klientas@pavyzdys.lt", "company_name": "UAB Pavyzdys", "company_number": "300000000", "tax_id": "LT100000000000", "first_name": "Vardas", "last_name": "Pavarde", "country": "LT", "language": "lt"}, "items": [{"product_id": 2872, "billing_cycle": "onetime", "quantity": 12}, {"product_id": 2877, "billing_cycle": "annually", "quantity": 12}], "reference": "PO-2026-001", "start_date": "2026-09-27", "send_emails": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerOrderResult"}, "example": {"customer_id": 4790, "customer_created": true, "order_id": 7205, "order_number": "ORD-202609-02011", "status": "pending", "invoice_id": 103402, "invoice_number": "ISF5209", "total": 3920.4, "currency": "EUR", "pay_url": "https://servera.lt/saskaita/3rChoki1M5MmS69oAZ05d0I4L3RX6CRw", "reference": "PO-2026-001"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "400": {"description": "Bad request \u2014 error is one of: no_items, too_many_items, product_not_allowed, invalid_cycle_for_product, product_not_found, idempotency_key_required"}, "409": {"description": "Conflict \u2014 error is customer_exists_not_owned (retry with link_if_exists=true, or an admin links via /admin/customers/partner-link)"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/products": {"get": {"tags": ["Partner Provisioning"], "summary": "List partner-allowed products with price breakdown", "description": "Return the products this partner may order, each with its full price breakdown\nso the partner can render an itemized cart. Devices are one-time and expose a\nline-by-line `breakdown` (what the customer pays for); the membership is recurring\nand exposes `pricing` per billing cycle plus a `split_per_cycle` (server vs SIM).\nPrices are net (excl. VAT); VAT is applied at order time.\n\nNames and breakdown labels are localized via the `lang` query parameter (or the\n`Accept-Language` header): cs, de, en, es, et, fi, fr, lt, lv, nl, pt \u2014 anything\nelse falls back to English. The chosen language is echoed as `lang`.", "operationId": "partner_products", "security": [{"ApiKey": []}], "parameters": [{"name": "lang", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Lang"}, "description": "Language for product names and breakdown labels: cs, de, en, es, et, fi, fr, lt, lv, nl, pt (falls back to English). May also be sent via the Accept-Language header."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerProductsResult"}, "example": {"vat_rate": 21.0, "note": "Prices are net (excl. VAT).", "products": [{"id": 2872, "name": "GPS Tracker (device)", "type": "onetime", "currency": "EUR", "price": 150.0, "billing_cycle": "onetime", "total_ex_vat": 150.0, "breakdown": [{"code": "2.2a", "label": "Device with factory configuration", "amount": 55.27}, {"code": "2.2b", "label": "Initial configuration", "amount": 23.73}, {"code": "2.2c", "label": "Registration and platform onboarding", "amount": 22.0}, {"code": "2.2d", "label": "IoT SIM issuance and activation", "amount": 18.0, "note": "one-time, not a data charge"}, {"code": "2.2e", "label": "Remote technical support activation", "amount": 12.0}, {"code": "2.2f", "label": "Firmware update service", "amount": 10.0}, {"code": "2.2g", "label": "Remote diagnostics and troubleshooting", "amount": 9.0}]}, {"id": 2877, "name": "Telemetry Membership", "type": "recurring", "currency": "EUR", "pricing": {"monthly": 13.0, "quarterly": 36.0, "semiannually": 66.0, "annually": 120.0, "biennially": 228.0, "triennially": 324.0}, "split_per_cycle": {"annually": {"server": 8.5, "sim": 1.5, "per_month": 10.0, "term": 120.0}}}]}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/orders": {"post": {"tags": ["Partner Provisioning"], "summary": "Place an order for an existing owned customer", "description": "Place a new order for a customer you already own (no customer creation). Same\npending-order + proforma flow as `/partner/provision`. `Idempotency-Key` required.", "operationId": "partner_orders_create", "security": [{"ApiKey": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerOrdersBody"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerOrderResult"}, "example": {"customer_id": 4790, "customer_created": false, "order_id": 7208, "order_number": "ORD-202609-02012", "status": "pending", "invoice_id": 103405, "invoice_number": "ISF5210", "total": 544.5, "currency": "EUR", "pay_url": "https://servera.lt/saskaita/aB0z..", "reference": "PO-2026-002"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "400": {"description": "Bad request \u2014 error is one of: no_items, too_many_items, product_not_allowed, invalid_cycle_for_product, product_not_found, idempotency_key_required"}, "404": {"description": "Not found \u2014 error is customer_not_found_or_not_owned"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/orders/{order_number}": {"get": {"tags": ["Partner Provisioning"], "summary": "Get one order's status", "description": "Status of one order you own \u2014 including whether its invoice is paid (so you can\ndetect a bank transfer landing and then create the account on your side).", "operationId": "partner_order_get", "security": [{"ApiKey": []}], "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string", "title": "Order Number"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerOrderInfo"}, "example": {"order_id": 7205, "order_number": "ORD-202609-02011", "status": "pending", "total": 3920.4, "currency": "EUR", "created_at": "2026-09-11T10:00:00", "invoice_id": 103402, "invoice_number": "ISF5209", "invoice_status": "unpaid", "paid": false}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "404": {"description": "Not found \u2014 error is order_not_found"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/customers": {"post": {"tags": ["Partner Provisioning"], "summary": "Create or update an end customer (no order)", "description": "Create an end customer, or update its requisites, WITHOUT placing an order \u2014\nfor pushing customer details to Servera before (or independently of) a purchase.\n\n- Email not in Servera \u2192 a new account is created (owned by you, verification email\n  sent) \u2192 `customer_created: true`.\n- Email exists and you own it \u2192 its requisites are updated \u2192 `customer_created: false`.\n- Email exists but you don't own it \u2192 adopted + updated when `link_if_exists: true`,\n  else `409 customer_exists_not_owned`.\n\nNaturally idempotent: the email identifies the account, so a retry updates the same\ncustomer rather than creating a duplicate. Returns the customer with `customer_id`\n(use it on later `/partner/orders`) and its `services`.", "operationId": "partner_customer_upsert", "security": [{"ApiKey": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerCustomerUpsertBody"}, "example": {"customer": {"email": "klientas@pavyzdys.lt", "company_name": "UAB Pavyzdys", "company_number": "300000000", "tax_id": "LT100000000000", "first_name": "Vardas", "last_name": "Pavard\u0117", "country": "LT", "language": "lt"}, "link_if_exists": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerCustomerInfo"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "409": {"description": "Conflict \u2014 error is customer_exists_not_owned (retry with link_if_exists=true, or an admin links via /admin/customers/partner-link)"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "get": {"tags": ["Partner Provisioning"], "summary": "Find an owned customer by email", "description": "Look up a customer you own by email (returns null if none/not owned). Use it to\ngreet a returning customer ('you already have a membership until \u2026') before the cart.", "operationId": "partner_customer_find", "security": [{"ApiKey": []}], "parameters": [{"name": "email", "in": "query", "required": true, "schema": {"type": "string", "description": "Customer email to look up \u2014 any email address of a customer you own (no domain restriction).", "title": "Email"}, "description": "Customer email to look up \u2014 any email address of a customer you own (no domain restriction)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/PartnerCustomerInfo"}, {"type": "null"}], "title": "Response Partner Customer Find"}, "example": {"customer_id": 4790, "email": "klientas@pavyzdys.lt", "company_name": "UAB Pavyzdys", "name": "Vardas Pavarde", "country": "LT", "language": "lt", "email_verified": false, "created_at": "2026-09-11T10:00:00", "services": [{"id": 14700, "product_id": 2877, "product_name": "Telemetry Membership", "status": "active", "billing_cycle": "annually", "recurring_amount": 120.0, "next_due_date": "2027-09-11", "registration_date": "2026-09-11"}]}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/customers/{customer_id}/services": {"get": {"tags": ["Partner Provisioning"], "summary": "List an owned customer's services", "description": "Services the customer already has (so you can show 'membership until \u2026' and decide\nwhether they are buying more).", "operationId": "partner_customer_services", "security": [{"ApiKey": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Customer Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/PartnerServiceInfo"}, "title": "Response Partner Customer Services"}, "example": [{"id": 14700, "product_id": 2877, "product_name": "Telemetry Membership", "status": "active", "billing_cycle": "annually", "recurring_amount": 120.0, "next_due_date": "2027-09-11", "registration_date": "2026-09-11"}]}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "404": {"description": "Not found \u2014 error is customer_not_found_or_not_owned"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/customers/{customer_id}/orders": {"get": {"tags": ["Partner Provisioning"], "summary": "List an owned customer's orders", "description": "Orders of a customer you own, optionally filtered by status or updated_since (ISO).", "operationId": "partner_customer_orders", "security": [{"ApiKey": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Customer Id"}}, {"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}, "description": "Filter by status."}, {"name": "updated_since", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Updated Since"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/PartnerOrderInfo"}, "title": "Response Partner Customer Orders"}, "example": [{"order_id": 7205, "order_number": "ORD-202609-02011", "status": "pending", "total": 3920.4, "currency": "EUR", "created_at": "2026-09-11T10:00:00", "invoice_id": 103402, "invoice_number": "ISF5209", "invoice_status": "paid", "paid": true}]}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "404": {"description": "Not found \u2014 error is customer_not_found_or_not_owned"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/customers/{customer_id}": {"patch": {"tags": ["Partner Provisioning"], "summary": "Update an owned customer's requisites", "description": "Update company/contact requisites on a customer you own (e.g. after the customer\nedits their profile in your app). Only provided fields change. Affects FUTURE invoices\nonly \u2014 already-issued invoices are immutable snapshots.", "operationId": "partner_customer_update", "security": [{"ApiKey": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Customer Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerCustomerPatch"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerCustomerInfo"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "404": {"description": "Not found \u2014 error is customer_not_found_or_not_owned"}, "400": {"description": "Bad request \u2014 error is no_fields"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/orders/{order_number}/cancel": {"post": {"tags": ["Partner Provisioning"], "summary": "Cancel an unpaid order", "description": "Cancel a still-unpaid order you own (and its proforma). Fails if already paid.", "operationId": "partner_order_cancel", "security": [{"ApiKey": []}], "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string", "title": "Order Number"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerCancelResult"}, "example": {"order_number": "ORD-202609-02011", "status": "cancelled"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "400": {"description": "Bad request \u2014 error is order_not_cancellable or order_already_paid"}, "404": {"description": "Not found \u2014 error is order_not_found"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/orders/{order_number}/pay": {"post": {"tags": ["Partner Provisioning"], "summary": "Settle an owned order with a confirmed Stripe PaymentIntent", "description": "Settle an owned order's proforma with a Stripe PaymentIntent (created by /pay-intent\nand confirmed on your page with Payment Element). Servera re-verifies the PI is\nsucceeded and matches the invoice amount, then converts the proforma to VAT, reconciles\nthe payment and activates the services \u2014 synchronously (you get `status: paid` back).", "operationId": "partner_order_pay", "security": [{"ApiKey": []}], "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string", "title": "Order Number"}}, {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerPayBody"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerPayResult"}, "example": {"invoice_id": 103402, "invoice_number": "SRV5746", "document_type": "vat", "converted_from_proforma": "ISF5209", "status": "paid", "is_paid": true, "method": "stripe_pi", "total": 3920.4, "currency": "EUR"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "400": {"description": "Bad request \u2014 error is order_has_no_invoice or payment_intent_id required"}, "402": {"description": "PI not usable \u2014 error is one of: pi_not_bound_to_order, pi_retrieve_failed, pi_not_succeeded, amount_mismatch, currency_mismatch, pi_invoice_mismatch, pi_already_used"}, "404": {"description": "Not found \u2014 error is order_not_found"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/partner/orders/{order_number}/pay-intent": {"post": {"tags": ["Partner Provisioning"], "summary": "Create a Stripe PaymentIntent for an owned order", "description": "Create a Stripe PaymentIntent for an owned order's unpaid proforma and return its\n`client_secret` + `publishable_key` + `mode`. Collect the card on your page with\nStripe.js Payment Element using these, confirm, then call POST \u2026/pay with the\n`payment_intent_id`. Single Stripe account \u2014 no Shared Payment Token needed.\n\nPass `mode` (\"live\" \u2014 default, or \"test\") to choose the environment per call: \"test\"\ncreates the PaymentIntent with the sandbox key set so you can dry-run a sale with a\nStripe test card (no real money). The chosen mode is pinned to the order, so the\nfollow-up /pay and any webhook confirmation process it with the matching keys.", "operationId": "partner_order_pay_intent", "security": [{"ApiKey": []}], "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string", "title": "Order Number"}}], "requestBody": {"content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/PartnerPayIntentBody"}, {"type": "null"}], "title": "Body"}, "example": {"mode": "test"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PartnerPayIntent"}, "example": {"payment_intent_id": "pi_3Qabc...", "client_secret": "pi_3Qabc..._secret_XYZ", "publishable_key": "pk_live_...", "mode": "live", "amount": 3920.4, "currency": "EUR", "invoice_id": 103402, "invoice_number": "ISF5209"}}}}, "401": {"description": "Unauthorized \u2014 missing or invalid API key"}, "403": {"description": "Forbidden \u2014 error is insufficient_scope (needs the partner:provision scope) or no_products_assigned"}, "400": {"description": "Bad request \u2014 error is order_has_no_invoice, order_not_payable, invalid_mode, mode_locked or stripe_not_configured"}, "404": {"description": "Not found \u2014 error is order_not_found"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/invoices/{invoice_id}/pay": {"post": {"tags": ["Orders"], "summary": "Pay an invoice (credit, card token, or bank transfer)", "description": "Pay one of your unpaid invoices (e.g. the proforma from a just-placed order).\n\nThree payment methods, all settling the invoice through the SAME engine the web\npanel uses - a successful payment triggers the exact same provisioning:\n\n- **`credit`** - pay from your account balance, **no browser step**. Returns **402**\n  with the amount due + `pay_url` if the balance doesn't cover the full total\n  (nothing is deducted in that case).\n- **`spt`** - charge a card programmatically with a Stripe **Shared Payment Token**\n  (`shared_payment_token`), **no browser step**. Built for agentic checkout: the\n  buyer's agent supplies a single-use, amount- and expiry-scoped token and we charge\n  that card directly. Declined charges leave the invoice unpaid.\n- **`bank_transfer`** - leave the invoice unpaid and return a `pay_url` for a human\n  to finish the payment in a browser.\n\nAn **`Idempotency-Key`** header is REQUIRED. An already-paid invoice returns success\nwithout charging again (natural idempotency).\n\nOn success the response carries the issued **VAT invoice**: `invoice_number` (the fiscal\ndocument number - the proforma is converted in place to a VAT invoice on payment),\n`document_type` (`vat`), `converted_from_proforma`, and the amount breakdown\n(`net` = be PVM, `vat`, `vat_rate` %, `gross` = su PVM; `total` = `gross`).\n\nThere is **no per-payment spend cap by default**; one is applied only if the\n`developer_api_max_charge` setting is configured to a positive number.", "operationId": "pay_invoice", "security": [{"ApiKey": []}], "parameters": [{"name": "invoice_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Invoice Id"}, "description": "Invoice id (from GET /invoices)."}, {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PayInvoiceBody"}, "example": {"method": "credit"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"invoice_id": 103361, "invoice_number": "BVPS404", "document_type": "vat", "converted_from_proforma": "SRD4026", "status": "paid", "is_paid": true, "method": "credit", "credit_applied": 7.85, "total": 7.85, "net": 6.49, "vat": 1.36, "vat_rate": 21.0, "gross": 7.85, "currency": "EUR", "order_number": "ORD-202608-01979"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/domains": {"get": {"tags": ["Domains"], "summary": "List domains", "description": "List your registered domains (status, expiry, nameservers, lock, DNSSEC).", "operationId": "list_domains", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"domains": [{"id": 15465, "domain": "example.com", "status": "Active", "tld": "com", "registrar": "OpenSRS", "registration_date": "2026-05-30", "expiry_date": "2027-05-30", "next_due_date": "2027-05-30", "registration_period": 1, "auto_renew": true, "dnssec_enabled": false, "transfer_locked": true, "nameservers": ["ns1.dedikuotas.lt", "ns2.dedikuotas.lt"], "recurring_amount": 12.0, "money_masked": false}]}}}}}, "security": [{"ApiKey": []}]}}, "/v1/domains/{domain_id}": {"get": {"tags": ["Domains"], "summary": "Get domain", "description": "One domain's details.", "operationId": "get_domain", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 15465, "domain": "example.com", "status": "Active", "tld": "com", "registrar": "OpenSRS", "registration_date": "2026-05-30", "expiry_date": "2027-05-30", "next_due_date": "2027-05-30", "registration_period": 1, "auto_renew": true, "dnssec_enabled": false, "transfer_locked": true, "nameservers": ["ns1.dedikuotas.lt", "ns2.dedikuotas.lt"], "recurring_amount": 12.0, "money_masked": false}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/domains/{domain_id}/dns": {"get": {"tags": ["Domains"], "summary": "Get DNS records", "description": "The DNS zone records for a domain you own (A/AAAA/CNAME/TXT/MX/\u2026).", "operationId": "get_dns_records", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"zone_exists": true, "domain": "example.com", "kind": "Master", "managed_dns": true, "records": [{"name": "@", "type": "A", "content": "185.209.139.4", "ttl": 3600, "priority": null}, {"name": "www", "type": "CNAME", "content": "example.com.", "ttl": 3600, "priority": null}, {"name": "@", "type": "MX", "content": "mail.example.com.", "ttl": 3600, "priority": 10}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/domains/{domain_id}/verification": {"get": {"tags": ["Domains"], "summary": "Domain contact email verification status", "description": "ICANN registrant/contact email-verification status for a domain you own\n(verifying/pending/verified/not_verified/suspended) plus the suspension\ndeadline. gTLDs only \u2014 ccTLDs report `supported: false`.", "operationId": "get_domain_verification", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/domains/{domain_id}/verification/resend": {"post": {"tags": ["Domains"], "summary": "Resend domain verification email", "description": "Resend the ICANN contact email-verification message for a domain you own.\nIf the contact email isn't verified before the deadline the domain is\nsuspended, so use this when the holder didn't receive the original email.", "operationId": "resend_domain_verification", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tag-catalog": {"get": {"tags": ["Tags"], "summary": "List the tag catalog", "description": "The predefined, grouped catalog of tags you can apply to services and domains.\nTag labels are international (English); category labels are localized by `lang`.", "operationId": "list_tag_catalog", "security": [{"ApiKey": []}], "parameters": [{"name": "lang", "in": "query", "required": false, "schema": {"type": "string", "default": "en", "title": "Lang"}, "description": "Language for product names and breakdown labels: cs, de, en, es, et, fi, fr, lt, lv, nl, pt (falls back to English). May also be sent via the Accept-Language header."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"groups": [{"category": "environment", "category_label": "Environment", "tags": [{"slug": "production", "label": "Production"}, {"slug": "staging", "label": "Staging"}]}, {"category": "platform", "category_label": "Platform", "tags": [{"slug": "wordpress", "label": "WordPress"}, {"slug": "laravel", "label": "Laravel"}]}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tags/{entity_type}/{entity_id}": {"get": {"tags": ["Tags"], "summary": "Get tags + comment", "description": "The tags and free-text comment on one of your services or domains.", "operationId": "get_entity_tags", "security": [{"ApiKey": []}], "parameters": [{"name": "entity_type", "in": "path", "required": true, "schema": {"enum": ["service", "domain"], "type": "string", "title": "Entity Type"}}, {"name": "entity_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Entity Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"tags": [{"tag": "production", "is_custom": false, "label": "Production", "category": "environment"}, {"tag": "wordpress", "is_custom": false, "label": "WordPress", "category": "platform"}, {"tag": "main client shop", "is_custom": true, "label": "main client shop", "category": null}], "comment": "Primary client shop. Upgrade PHP to 8.3 next month."}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Tags"], "summary": "Set tags + comment", "description": "Replace the tags (when `tags` is provided) and set/clear the comment (when\n`set_comment` is true) on one of your services or domains. The comment is visible\nto you and to Servera staff.", "operationId": "set_entity_tags", "security": [{"ApiKey": []}], "parameters": [{"name": "entity_type", "in": "path", "required": true, "schema": {"enum": ["service", "domain"], "type": "string", "title": "Entity Type"}}, {"name": "entity_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Entity Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DevTagsBody"}, "example": {"tags": ["production", "wordpress", "main client shop"], "comment": "Primary client shop. Upgrade PHP to 8.3 next month.", "set_comment": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"tags": [{"tag": "production", "is_custom": false, "label": "Production", "category": "environment"}], "comment": "Primary client shop."}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tagged/{tag}": {"get": {"tags": ["Tags"], "summary": "Find entities by tag", "description": "List the services and domains that carry a given tag (catalog slug or custom text).", "operationId": "find_entities_by_tag", "security": [{"ApiKey": []}], "parameters": [{"name": "tag", "in": "path", "required": true, "schema": {"type": "string", "title": "Tag"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"tag": "production", "matches": [{"entity_type": "service", "entity_id": 15231, "name": "example.lt"}, {"entity_type": "domain", "entity_id": 40118, "name": "shop.example.lt"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tickets": {"get": {"tags": ["Tickets"], "summary": "List tickets", "description": "List your support tickets (most-recently-active first). Optional `status` filter.", "operationId": "list_tickets", "security": [{"ApiKey": []}], "parameters": [{"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}, "description": "Filter by status."}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}, "description": "Row offset for pagination (default 0)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"tickets": [{"id": 2368, "number": "TKT-20260501-FA705A", "subject": "DB error", "priority": "medium", "status": "closed", "status_name": "Closed", "department": "Support", "reply_count": 3, "unread": false, "created_at": "2026-05-01T09:00:00+00:00", "last_reply_at": "2026-05-02T14:00:00+00:00"}], "total": 7, "limit": 50, "offset": 0}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["Tickets"], "summary": "Open a ticket", "description": "Open a new support ticket. Notifies staff exactly like the customer area.", "operationId": "create_ticket", "security": [{"ApiKey": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TicketCreate"}, "example": {"department_id": 1, "subject": "Disk almost full", "message": "My VPS is running low on disk \u2014 please advise.", "priority": "medium"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "ticket_id": 2400, "ticket_number": "TKT-20260819-ABC123"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tickets/{ticket_id}": {"get": {"tags": ["Tickets"], "summary": "Get ticket", "description": "One ticket with its full reply thread.", "operationId": "get_ticket", "security": [{"ApiKey": []}], "parameters": [{"name": "ticket_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Ticket Id"}, "description": "Ticket id (from GET /tickets)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 2368, "number": "TKT-20260501-FA705A", "subject": "DB error", "message": "My database won't connect.", "priority": "medium", "status": "closed", "status_name": "Closed", "department": "Support", "created_at": "2026-05-01T09:00:00+00:00", "last_reply_at": "2026-05-02T14:00:00+00:00", "replies": [{"id": 31, "message": "We've restarted the service.", "from": "staff", "author": "Support Agent", "created_at": "2026-05-02T14:00:00+00:00"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/tickets/{ticket_id}/reply": {"post": {"tags": ["Tickets"], "summary": "Reply to a ticket", "description": "Post a reply on one of your tickets.", "operationId": "reply_ticket", "security": [{"ApiKey": []}], "parameters": [{"name": "ticket_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Ticket Id"}, "description": "Ticket id (from GET /tickets)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TicketReply"}, "example": {"message": "Thanks, that resolved it."}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "reply_id": 52}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/domains/{domain_id}/dns/records": {"post": {"tags": ["Domains"], "summary": "Add DNS record", "description": "Add a DNS record to a domain you own (PowerDNS-hosted zones).", "operationId": "add_dns_record", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsRecordCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Domains"], "summary": "Update DNS record", "description": "Update a DNS record (identify it by its current name/type/content).", "operationId": "update_dns_record", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsRecordUpdate"}, "example": {"old_name": "www", "old_type": "A", "old_content": "185.209.139.4", "new_name": "www", "new_type": "A", "new_content": "185.209.139.5", "ttl": 3600}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["Domains"], "summary": "Delete DNS record", "description": "Delete a DNS record (pass its name, type and content as query params).", "operationId": "delete_dns_record", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}, {"name": "name", "in": "query", "required": true, "schema": {"type": "string", "title": "Name"}, "description": "DNS record name \u2014 `@` for the apex, or a subdomain label."}, {"name": "type", "in": "query", "required": true, "schema": {"type": "string", "title": "Type"}, "description": "DNS record type (A, AAAA, CNAME, MX, TXT, SRV, CAA) \u2014 identifies the record to delete."}, {"name": "content", "in": "query", "required": true, "schema": {"type": "string", "title": "Content"}, "description": "The record's exact content/value \u2014 identifies the record to delete."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/users": {"get": {"tags": ["Users"], "summary": "List account users", "description": "List the users on your account (owner + invited sub-users).", "operationId": "list_users", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"users": [{"id": 489, "email": "owner@example.com", "first_name": "Jane", "last_name": "Doe", "is_owner": true, "has_2fa": true, "permissions": [], "last_login_at": "2026-08-18T08:00:00+00:00", "created_at": "2025-01-10T12:00:00+00:00", "invitation_pending": false}]}}}}}, "security": [{"ApiKey": []}]}}, "/v1/users/invite": {"post": {"tags": ["Users"], "summary": "Invite a user", "description": "Invite a user by email (owner only). Sends an invitation email with the granted permissions.", "operationId": "invite_user", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserInvite"}, "example": {"email": "colleague@example.com", "permissions": ["products", "invoices"]}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "id": 512, "email": "colleague@example.com"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/users/{user_id}/resend-invitation": {"post": {"tags": ["Users"], "summary": "Resend invitation", "description": "Resend a pending invitation email.", "operationId": "resend_invitation", "security": [{"ApiKey": []}], "parameters": [{"name": "user_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "User Id"}, "description": "Account user id (from GET /users)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "message": "invitation_resent"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/emails": {"get": {"tags": ["Emails"], "summary": "List system emails", "description": "The transactional/system emails sent to your account (invoices, notifications, \u2026).", "operationId": "list_system_emails", "security": [{"ApiKey": []}], "parameters": [{"name": "page", "in": "query", "required": false, "schema": {"type": "integer", "default": 1, "title": "Page"}, "description": "Page number, 1-based (default 1)."}, {"name": "per_page", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Per Page"}, "description": "Rows per page (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"emails": [{"id": 900, "to": "you@example.com", "subject": "Invoice SRV-2026-000123", "status": "sent", "related_type": "invoice", "related_id": 103302, "template": "invoice_email", "failed": false, "has_attachments": true, "created_at": "2026-08-01T10:01:00+00:00"}], "total": 54, "page": 1, "per_page": 50}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/emails/{email_id}": {"get": {"tags": ["Emails"], "summary": "Get system email", "description": "One system email, including its rendered body.", "operationId": "get_system_email", "security": [{"ApiKey": []}], "parameters": [{"name": "email_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Email Id"}, "description": "System-email id (from GET /emails)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 900, "to": "you@example.com", "subject": "Invoice SRV-2026-000123", "body": "<html>\u2026invoice email\u2026</html>", "status": "sent", "related_type": "invoice", "related_id": 103302, "template": "invoice_email", "failed": false, "attachments": [{"filename": "invoice.pdf", "size": 48213}], "created_at": "2026-08-01T10:01:00+00:00"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/security/ip-status": {"get": {"tags": ["Security"], "summary": "Is my IP blocked?", "description": "Whether the caller's current IP is blocked on any of your shared-hosting servers.", "operationId": "ip_status", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ip": "203.0.113.7", "blocked": false, "ip_info": {"asn": "AS3320", "as_org": "Example ISP", "country": "DE", "country_code": "DE", "hostname": "host.example.net"}}}}}}, "security": [{"ApiKey": []}]}}, "/v1/security/ip-check": {"get": {"tags": ["Security"], "summary": "Check an IP", "description": "Check whether a specific IP is blocked on any of your shared-hosting servers.", "operationId": "ip_check", "security": [{"ApiKey": []}], "parameters": [{"name": "ip", "in": "query", "required": false, "schema": {"type": "string", "default": "", "title": "Ip"}, "description": "IP address to check. For mail RBL-check this may also be a sender address/domain."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ip": "203.0.113.7", "valid": true, "blocked": true, "ip_info": {"asn": "AS3320", "country": "DE"}, "block": {"block_type": "temp", "reason_category": "login_failures", "expires_at": "2026-08-19T12:00:00+00:00"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/security/unblock": {"post": {"tags": ["Security"], "summary": "Unblock an IP", "description": "Unblock an IP on your shared-hosting servers. Defaults to your current IP;\nan explicit `ip` is honored only if it is actually blocked on your servers.\nRate-limited (5 per hour).", "operationId": "ip_unblock", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UnblockRequest"}, "example": {"ip": "203.0.113.7"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "unblocked": 1, "ip": "203.0.113.7"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/security/history": {"get": {"tags": ["Security"], "summary": "IP block history", "description": "Your block/unblock history.", "operationId": "ip_history", "security": [{"ApiKey": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"items": [{"ip": "203.0.113.7", "action": "unblock", "reason_category": "login_failures", "actor_type": "customer", "created_at": "2026-08-19T11:00:00+00:00"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/vps/{service_id}/firewall/rules/{pos}/move": {"post": {"tags": ["VPS"], "summary": "Reorder firewall rule", "description": "Move the rule at `pos` to position `moveto`.", "operationId": "move_firewall_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FirewallRuleMove"}, "example": {"moveto": 0}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "from": 2, "to": 0}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/networks": {"get": {"tags": ["Networks"], "summary": "List VPC networks", "description": "List your VPC networks.", "operationId": "list_networks", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"networks": [{"id": 1, "cidr": "10.80.6.0/24", "gateway": "10.80.6.1/32", "status": "active", "attached_vms": 6, "created_at": "2026-05-30T01:41:00+00:00"}]}}}}}, "security": [{"ApiKey": []}]}}, "/v1/networks/{vpc_id}/firewall": {"get": {"tags": ["Networks"], "summary": "Get VPC firewall", "description": "The VPC's firewall state + rules.", "operationId": "get_vpc_firewall", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"vpc": {"id": 1, "cidr": "10.80.6.0/24", "gateway": "10.80.6.1/32"}, "enabled": true, "policy_forward": "ACCEPT", "internal_allowed": true, "rules": [{"pos": 0, "type": "forward", "action": "ACCEPT", "enable": 1}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/networks/{vpc_id}/firewall/options": {"put": {"tags": ["Networks"], "summary": "Set VPC firewall options", "operationId": "set_vpc_firewall_options", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VpcFwOptions"}, "example": {"enable": 1, "policy_forward": "ACCEPT"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Set a VPC firewall's options \u2014 enable it and its FORWARD policy (ACCEPT/DROP)."}}, "/v1/networks/{vpc_id}/firewall/rules": {"post": {"tags": ["Networks"], "summary": "Add VPC firewall rule", "operationId": "add_vpc_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VpcRule"}, "example": {"type": "forward", "action": "ACCEPT", "proto": "tcp", "dport": "443"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Add a rule to a VPC network's firewall. `type` is `in`, `out` or `forward`."}}, "/v1/networks/{vpc_id}/firewall/rules/{pos}": {"put": {"tags": ["Networks"], "summary": "Update VPC firewall rule", "operationId": "update_vpc_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VpcRule"}, "example": {"type": "forward", "action": "DROP", "source": "10.80.6.0/24", "dest": "10.80.6.0/24"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Replace the VPC firewall rule at position `pos`."}, "delete": {"tags": ["Networks"], "summary": "Delete VPC firewall rule", "operationId": "delete_vpc_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Delete the VPC firewall rule at position `pos`."}}, "/v1/networks/{vpc_id}/firewall/internal-traffic": {"put": {"tags": ["Networks"], "summary": "Allow/block VM\u2194VM traffic", "description": "Allow or block east-west (VM\u2194VM) traffic without breaking behind-router north-south.", "operationId": "set_internal_traffic", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/InternalTraffic"}, "example": {"allow": false}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "internal_allowed": false}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/networks/{vpc_id}/firewall/rules/{pos}/move": {"post": {"tags": ["Networks"], "summary": "Reorder VPC firewall rule", "operationId": "move_vpc_rule", "security": [{"ApiKey": []}], "parameters": [{"name": "vpc_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Vpc Id"}, "description": "VPC network id (from GET /networks)."}, {"name": "pos", "in": "path", "required": true, "schema": {"type": "integer", "title": "Pos"}, "description": "Firewall-rule position, 0-based (as returned by the firewall read)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RuleMoveTo"}, "example": {"to": 0}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "from": 2, "to": 0}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Move a VPC firewall rule to a new position (`to`, 0-based)."}}, "/v1/virtual-routers": {"get": {"tags": ["Virtual Router"], "summary": "List Virtual Routers", "description": "List your Virtual Routers.", "operationId": "list_virtual_routers", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"virtual_routers": [{"service_id": 14700, "label": "router1", "status": "active", "vr_status": "active", "plan": "vr-small", "wan_ip": "185.209.138.50", "wan_ip6": "2a0e:1200::50"}]}}}}}, "security": [{"ApiKey": []}]}}, "/v1/virtual-routers/{service_id}": {"get": {"tags": ["Virtual Router"], "summary": "Get Virtual Router", "description": "Virtual Router overview - WAN, WireGuard peers, public-IP mappings, quota.", "operationId": "get_virtual_router", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"service_id": 14700, "plan": "vr-small", "status": "active", "wan_ip": "185.209.138.50", "wan_ip6": "2a0e:1200::50", "wireguard": {"port": 51820, "peers": [{"id": 1, "name": "laptop", "allowed_ip": "10.80.7.2/32", "created_at": "2026-06-01T10:00:00+00:00"}]}, "public_ips": [{"id": 1, "public_ip": "185.209.138.51", "private_ip": "10.80.6.10", "created_at": "2026-06-01T10:00:00+00:00"}], "public_ipv4": {"quota": 2, "used": 1}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/virtual-routers/{service_id}/wireguard": {"get": {"tags": ["Virtual Router"], "summary": "List WireGuard peers", "operationId": "list_wg_peers", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"peers": [{"id": 1, "name": "laptop", "allowed_ip": "10.80.7.2/32", "created_at": "2026-06-01T10:00:00+00:00"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "List the WireGuard peers configured on a Virtual Router."}, "post": {"tags": ["Virtual Router"], "summary": "Add WireGuard peer", "description": "Add a WireGuard peer. If you omit `public_key`, one is generated and the config is returned once.", "operationId": "add_wg_peer", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WgPeer"}, "example": {"name": "laptop"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"peer_id": 2, "name": "phone", "client_ip": "10.80.7.3/32", "generated": true, "config": "[Interface]\nPrivateKey=\u2026\nAddress=10.80.7.3/32\n[Peer]\n\u2026"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/virtual-routers/{service_id}/wireguard/{peer_id}": {"delete": {"tags": ["Virtual Router"], "summary": "Remove WireGuard peer", "operationId": "remove_wg_peer", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "peer_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Peer Id"}, "description": "WireGuard peer id (from GET \u2026/wireguard)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"removed": true, "peer_id": 2}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Remove a WireGuard peer from a Virtual Router."}}, "/v1/virtual-routers/{service_id}/public-ips": {"get": {"tags": ["Virtual Router"], "summary": "List public IPs", "operationId": "list_public_ips", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"public_ips": [{"id": 1, "public_ip": "185.209.138.51", "private_ip": "10.80.6.10", "created_at": "2026-06-01T10:00:00+00:00"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "List the public-IP \u2192 private-IP mappings on a Virtual Router."}, "post": {"tags": ["Virtual Router"], "summary": "Map a public IP", "description": "Map a public IPv4 to a private IP behind the router (subject to your quota).", "operationId": "add_public_ip", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicIpMap"}, "example": {"private_ip": "10.80.6.10"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "public_ip_id": 2, "public_ip": "185.209.138.52", "private_ip": "10.80.6.11"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/virtual-routers/{service_id}/attachable-vms": {"get": {"tags": ["Virtual Router"], "summary": "List attachable VMs", "operationId": "attachable_vms", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"vms": [{"service_id": 14684, "name": "web1", "hostname": "web1.example.com", "status": "active", "running": true, "attached": false, "private_ipv4": null, "public_ipv4": "185.209.138.106"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "List your VMs that can be moved behind this Virtual Router."}}, "/v1/virtual-routers/{service_id}/attach-vm": {"post": {"tags": ["Virtual Router"], "summary": "Attach a VM", "description": "Move one of your VMs behind this Virtual Router.", "operationId": "attach_vm", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AttachVm"}, "example": {"target_service_id": 14684}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"behind": true, "public_ipv4": "185.209.138.51", "private_ipv4": "10.80.6.10"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/virtual-routers/{service_id}/detach-vm": {"post": {"tags": ["Virtual Router"], "summary": "Detach a VM", "description": "Restore one of your VMs to standalone (public) networking.", "operationId": "detach_vm", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AttachVm"}, "example": {"target_service_id": 14684}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"public_ipv4": "185.209.138.106"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/mail/servers": {"get": {"tags": ["Mail"], "summary": "List mail servers", "description": "Mail-enabled servers hosting your domains, with the domains on each.", "operationId": "mail_servers", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "servers": [{"server_id": 96, "domains": ["example.com"]}], "can_manage": true}}}}}, "security": [{"ApiKey": []}]}}, "/v1/mail/rbl-check": {"get": {"tags": ["Mail"], "summary": "RBL / blocklist check", "description": "Check an IP (or a sender address/domain) against DNS blocklists across your mail servers.", "operationId": "mail_rbl_check", "security": [{"ApiKey": []}], "parameters": [{"name": "ip", "in": "query", "required": false, "schema": {"type": "string", "default": "", "title": "Ip"}, "description": "IP address to check. For mail RBL-check this may also be a sender address/domain."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "ip": "203.0.113.7", "sender": null, "listed": false, "listings": [], "whitelisted": false, "ip_info": {"asn": "AS3320", "country": "DE"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/mail/coverage": {"get": {"tags": ["Mail"], "summary": "Mail-log coverage", "description": "How far back the delivery-log search reaches.", "operationId": "mail_coverage", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "oldest": "2026-07-01T00:00:00", "newest": "2026-08-19T09:00:00"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/mail/trace": {"get": {"tags": ["Mail"], "summary": "Delivery trace", "description": "Search your mail delivery log - was a message sent, blocked, or RBL-rejected.", "operationId": "mail_trace", "security": [{"ApiKey": []}], "parameters": [{"name": "q", "in": "query", "required": false, "schema": {"type": "string", "default": "", "title": "Q"}, "description": "Free-text filter \u2014 an address, IP, or subject fragment."}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 60, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "domains": ["example.com"], "entries": [{"time": "2026-08-19 09:12:03", "from": "sender@other.com", "to": "you@example.com", "status": "ok"}], "home_cc": "LT", "multi_server": false}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/mail/history": {"get": {"tags": ["Mail"], "summary": "Mail action history", "description": "Your mail protection action history (whitelists, checks, trusted, \u2026).", "operationId": "mail_history", "security": [{"ApiKey": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "events": [{"action": "rbl_check", "ip": "203.0.113.7", "at": "2026-08-19T09:00:00+00:00"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/mail/whitelist": {"get": {"tags": ["Mail"], "summary": "List RBL whitelist", "description": "Your self-whitelisted sender IPs + today's remaining quota.", "operationId": "mail_whitelist_list", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "entries": [{"id": 5, "ip": "203.0.113.7", "added_at": "2026-08-10T10:00:00+00:00"}], "daily_limit": 10, "used_today": 0, "remaining_today": 10, "can_manage": true}}}}}, "security": [{"ApiKey": []}]}, "post": {"tags": ["Mail"], "summary": "Whitelist a sender IP", "description": "Whitelist a sender IP (only if it was recently RBL-rejected to your own domain). Rate-limited.", "operationId": "mail_whitelist_add", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WhitelistAdd"}, "example": {"ip": "203.0.113.7", "reason": "our office mail server"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "applied": true, "ip": "203.0.113.7", "server_id": 96, "id": 5, "domains": ["example.com"], "remaining_today": 9}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/mail/whitelist/{wl_id}": {"delete": {"tags": ["Mail"], "summary": "Remove whitelist entry", "operationId": "mail_whitelist_remove", "security": [{"ApiKey": []}], "parameters": [{"name": "wl_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Wl Id"}, "description": "RBL-whitelist entry id (from GET /mail/whitelist)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "removed": true, "ip": "203.0.113.7"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Remove one of your RBL-whitelist entries by its id."}}, "/v1/mail/trusted": {"get": {"tags": ["Mail"], "summary": "List trusted senders", "description": "Trusted senders per mail account (always accepted, never spam-flagged).", "operationId": "mail_trusted_list", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "accounts": [{"server_id": 96, "cpanel_user": "exampl", "domain": "example.com", "platform": "cpanel", "entries": ["good@sender.com"], "reachable": true}], "can_manage": true, "max_per_account": 50}}}}}, "security": [{"ApiKey": []}]}, "post": {"tags": ["Mail"], "summary": "Add trusted sender", "operationId": "mail_trusted_add", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TrustedSender"}, "example": {"server_id": 96, "cpanel_user": "exampl", "sender": "good@sender.com"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "added": true, "sender": "good@sender.com"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}], "description": "Add a trusted sender (email, `*@domain`, or a bare domain) \u2014 its mail is always accepted and never spam-flagged."}}, "/v1/mail/trusted/remove": {"post": {"tags": ["Mail"], "summary": "Remove trusted sender", "operationId": "mail_trusted_remove", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TrustedSender"}, "example": {"server_id": 96, "cpanel_user": "exampl", "sender": "good@sender.com"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "removed": true, "sender": "good@sender.com"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}], "description": "Remove a trusted sender from a mail account."}}, "/v1/mail/autoresponders": {"get": {"tags": ["Mail"], "summary": "List autoresponders", "description": "Your mailboxes and which have an autoresponder set.", "operationId": "mail_ar_list", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "accounts": [{"server_id": 96, "cpanel_user": "exampl", "domain": "example.com", "mailboxes": [{"email": "info@example.com", "has_ar": true, "subject": "On vacation"}]}], "can_manage": true}}}}}, "security": [{"ApiKey": []}]}, "put": {"tags": ["Mail"], "summary": "Set autoresponder", "description": "Create or update the autoresponder for one of your mailboxes.", "operationId": "mail_ar_set", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Autoresponder"}, "example": {"email": "info@example.com", "subject": "On vacation", "body": "I'm away until Monday and will reply then.", "interval": 24}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "email": "info@example.com"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/mail/autoresponders/get": {"get": {"tags": ["Mail"], "summary": "Get autoresponder", "operationId": "mail_ar_get", "security": [{"ApiKey": []}], "parameters": [{"name": "email", "in": "query", "required": false, "schema": {"type": "string", "default": "", "title": "Email"}, "description": "Mailbox address \u2014 must be on a domain you own on a cPanel server."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "autoresponder": {"subject": "On vacation", "body": "Back on Monday.", "interval": 24}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Get the autoresponder configured on one of your mailboxes."}}, "/v1/mail/autoresponders/delete": {"post": {"tags": ["Mail"], "summary": "Turn off autoresponder", "operationId": "mail_ar_delete", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmailRef"}, "example": {"email": "info@example.com"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"ok": true, "email": "info@example.com", "removed": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}], "description": "Turn off the autoresponder on one of your mailboxes."}}, "/v1/contacts": {"get": {"tags": ["Contacts"], "summary": "List contacts", "description": "List your account contacts.", "operationId": "list_contacts", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"contacts": [{"id": 10, "first_name": "Jane", "last_name": "Doe", "company_name": "Acme", "company_code": "123", "email": "jane@example.com", "phone": "+37060000000", "tax_id": "LT100000000", "address1": "Gedimino 1", "address2": "", "city": "Vilnius", "state": "", "postcode": "01100", "country": "LT", "general_emails": true, "invoice_emails": true, "support_emails": true, "product_emails": true, "domain_emails": true, "affiliate_emails": false, "is_owner": true}]}}}}}, "security": [{"ApiKey": []}]}, "post": {"tags": ["Contacts"], "summary": "Create contact", "operationId": "create_contact", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactData"}, "example": {"first_name": "John", "last_name": "Smith", "email": "john@example.com", "country": "LT", "invoice_emails": true}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "contact_id": 11}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}], "description": "Add a contact to your account."}}, "/v1/contacts/{contact_id}": {"get": {"tags": ["Contacts"], "summary": "Get contact", "operationId": "get_contact", "security": [{"ApiKey": []}], "parameters": [{"name": "contact_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Contact Id"}, "description": "Account contact id (from GET /contacts)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 10, "first_name": "Jane", "last_name": "Doe", "company_name": "Acme", "company_code": "123", "email": "jane@example.com", "phone": "+37060000000", "tax_id": "LT100000000", "address1": "Gedimino 1", "address2": "", "city": "Vilnius", "state": "", "postcode": "01100", "country": "LT", "general_emails": true, "invoice_emails": true, "support_emails": true, "product_emails": true, "domain_emails": true, "affiliate_emails": false, "is_owner": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Get one account contact by id."}, "put": {"tags": ["Contacts"], "summary": "Update contact", "operationId": "update_contact", "security": [{"ApiKey": []}], "parameters": [{"name": "contact_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Contact Id"}, "description": "Account contact id (from GET /contacts)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactData"}, "example": {"first_name": "John", "last_name": "Smith", "email": "john@example.com", "country": "LT"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Update an account contact."}, "delete": {"tags": ["Contacts"], "summary": "Delete contact", "description": "Delete a contact (the owner contact can't be deleted).", "operationId": "delete_contact", "security": [{"ApiKey": []}], "parameters": [{"name": "contact_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Contact Id"}, "description": "Account contact id (from GET /contacts)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/logs": {"get": {"tags": ["Logs"], "summary": "Activity log", "description": "Your account activity log (audited actions), with optional category filter and search.", "operationId": "list_logs", "security": [{"ApiKey": []}], "parameters": [{"name": "category", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Category"}, "description": "Filter the activity log by category (e.g. service, account, domain, security)."}, {"name": "search", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Search"}, "description": "Free-text search across the description, action and category."}, {"name": "page", "in": "query", "required": false, "schema": {"type": "integer", "default": 1, "title": "Page"}, "description": "Page number, 1-based (default 1)."}, {"name": "per_page", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Per Page"}, "description": "Rows per page (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"logs": [{"id": 815, "action": "vm_start", "category": "service", "description": "VM start via api", "related_type": "service", "related_id": 14684, "metadata": {"actor": "api"}, "ip_address": "203.0.113.7", "by_customer": true, "by_staff": false, "created_at": "2026-08-19T09:00:00+00:00"}], "categories": [{"category": "service", "count": 400}, {"category": "account", "count": 200}], "total": 815, "page": 1, "per_page": 50}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains": {"get": {"tags": ["WAF"], "summary": "List WAF domains", "description": "Your WAF bindings (whether the protection is on or off).", "operationId": "list_waf_domains", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"domains": [{"id": 3, "domain": "example.com", "status": "active", "enabled_at": "2026-07-01T10:00:00+00:00", "disabled_at": null, "dns_flipped_at": "2026-07-01T10:05:00+00:00", "cert_acquired_at": "2026-07-01T10:03:00+00:00", "failed_at": null, "error_message": null}]}}}}}, "security": [{"ApiKey": []}]}, "post": {"tags": ["WAF"], "summary": "Create WAF binding", "description": "Create a WAF binding for a domain you own (idempotent - returns the existing one).", "operationId": "waf_create_binding", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafBindingCreate"}, "example": {"domain": "example.com"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 3, "domain": "example.com", "status": "pending", "created": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/waf/domains/{waf_domain_id}/security": {"get": {"tags": ["WAF"], "summary": "WAF security state", "description": "Threat-filtering engine state + active security preset for a WAF domain.", "operationId": "waf_security", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "engine_on": true, "active_preset": "balanced", "available_presets": ["off", "basic", "balanced", "strict"], "service_present": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/security/engine": {"post": {"tags": ["WAF"], "summary": "Toggle threat filtering", "description": "Turn the WAF threat-filtering (ModSecurity) engine on or off for a domain.", "operationId": "waf_toggle_engine", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafEngine"}, "example": {"enabled": true}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "enabled": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/enable": {"post": {"tags": ["WAF"], "summary": "Enable WAF", "description": "Turn the WAF on for a domain (routes it through the Servera edge). Runs\nasynchronously - poll the status endpoint.", "operationId": "waf_enable", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafEnable"}, "example": {"reverse_proxy_host": null}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "accepted": true, "poll": "/v1/waf/domains/3/status"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/disable": {"post": {"tags": ["WAF"], "summary": "Disable WAF", "description": "Turn the WAF off for a domain.", "operationId": "waf_disable", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "accepted": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/logs": {"get": {"tags": ["WAF"], "summary": "WAF traffic logs", "description": "Recent WAF traffic logs for a domain (hours: 1-720).", "operationId": "waf_logs", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}, {"name": "hours", "in": "query", "required": false, "schema": {"type": "integer", "default": 24, "title": "Hours"}, "description": "Look-back window in hours (1\u2013720)."}, {"name": "status_min", "in": "query", "required": false, "schema": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Status Min"}, "description": "Only include log lines with an HTTP status code \u2265 this."}, {"name": "status_max", "in": "query", "required": false, "schema": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Status Max"}, "description": "Only include log lines with an HTTP status code \u2264 this."}, {"name": "cache_status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Cache Status"}, "description": "Filter WAF logs by cache result (HIT, MISS, BYPASS, EXPIRED, \u2026)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"logs": [{"time": "2026-08-19T09:00:00", "ip": "203.0.113.7", "status": 403, "method": "GET", "url": "/wp-login.php", "country": "US"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/security/preset-components": {"get": {"tags": ["WAF"], "summary": "Preset components", "description": "What a security preset does, broken into toggleable rule components.", "operationId": "waf_preset_components", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}, {"name": "key", "in": "query", "required": true, "schema": {"type": "string", "title": "Key"}, "description": "Security-preset key (e.g. `basic`, `balanced`, `strict`)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"key": "balanced", "components": [{"id": "sqli", "label": "SQL injection", "rules": ["942100"]}], "disabled": []}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/security/preset": {"post": {"tags": ["WAF"], "summary": "Apply security preset", "description": "Apply a security preset (optionally switching off named rule components).", "operationId": "waf_apply_preset", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafPreset"}, "example": {"preset": "balanced", "disabled_components": []}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "applied_preset": "balanced", "disabled": []}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/advanced": {"get": {"tags": ["WAF"], "summary": "Get advanced rules", "description": "Advanced-mode custom rules (bypass endpoints + rule exclusions).", "operationId": "waf_get_advanced", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "active_preset": "balanced", "bypass": [], "exclusions": []}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["WAF"], "summary": "Set advanced rules", "operationId": "waf_put_advanced", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafAdvanced"}, "example": {"bypass": ["/health"], "exclusions": []}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "bypass": [], "exclusions": []}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Save and apply advanced WAF rules \u2014 custom bypass endpoints and rule exclusions."}}, "/v1/waf/domains/{waf_domain_id}/bot-policy": {"get": {"tags": ["WAF"], "summary": "Get bot policy", "description": "Known-bot catalog + this domain's allow/block choice for each.", "operationId": "waf_bot_policy_get", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "catalog": [{"key": "googlebot", "group": "search", "label": "Googlebot", "default": "allow"}], "policy": {"googlebot": "allow"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["WAF"], "summary": "Set bot policy", "operationId": "waf_bot_policy_set", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafBotPolicy"}, "example": {"policy": {"googlebot": "allow", "gptbot": "block"}}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "policy": {"googlebot": "allow"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Set the per-bot allow/block policy for a WAF domain (a partial map is fine \u2014 unset bots keep their default)."}}, "/v1/waf/domains/{waf_domain_id}/lists": {"get": {"tags": ["WAF"], "summary": "Get IP/country lists", "description": "Allow/block lists (IP and country) for a WAF domain.", "operationId": "waf_lists_get", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "lists": {"ip-allow": {"count": 1, "entries": [{"value": "203.0.113.7", "comment": "office"}]}, "ip-block": {"count": 0, "entries": []}, "country-allow": {"count": 0, "entries": []}, "country-block": {"count": 1, "entries": [{"value": "CN", "comment": ""}]}}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/lists/{kind}": {"put": {"tags": ["WAF"], "summary": "Replace a list", "description": "Replace a list. `kind`: ip-allow | ip-block | country-allow | country-block.", "operationId": "waf_lists_set", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}, {"name": "kind", "in": "path", "required": true, "schema": {"type": "string", "title": "Kind"}, "description": "List kind: `ip-allow`, `ip-block`, `country-allow`, or `country-block`."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WafListEntries"}, "example": {"entries": [{"value": "203.0.113.7", "comment": "office"}]}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"waf_domain_id": 3, "kind": "ip-allow", "entries": [{"value": "203.0.113.7", "comment": "office"}], "mirror_ok": true}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domain-map": {"get": {"tags": ["WAF"], "summary": "Domain \u2192 WAF binding map", "description": "Every domain you own mapped to its WAF binding (null = no binding / WAF off).", "operationId": "waf_domain_map", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"map": {"example.com": {"id": 3, "domain": "example.com", "status": "active", "enabled_at": "2026-07-01T10:00:00+00:00", "disabled_at": null, "failed_at": null, "error_message": null}, "another.com": null}}}}}}, "security": [{"ApiKey": []}]}}, "/v1/waf/domains/{waf_domain_id}/status": {"get": {"tags": ["WAF"], "summary": "WAF toggle status", "description": "Enable/disable progress + DNS propagation state (poll after enable/disable).", "operationId": "waf_status", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"id": 3, "domain": "example.com", "status": "active", "dns_flipped_at": "2026-07-01T10:05:00+00:00", "propagation_remaining_s": 1800}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/waf/domains/{waf_domain_id}/ns-check": {"get": {"tags": ["WAF"], "summary": "Nameserver pre-flight", "description": "Check whether the domain uses Servera nameservers (needed before enabling the WAF).", "operationId": "waf_ns_check", "security": [{"ApiKey": []}], "parameters": [{"name": "waf_domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Waf Domain Id"}, "description": "WAF binding id (from GET /waf/domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"domain": "example.com", "uses_our_ns": true, "seen": ["ns1.dedikuotas.lt"], "expected_any_of": ["ns1.dedikuotas.lt", "ns2.dedikuotas.lt"], "expected_groups": [["ns1.dedikuotas.lt", "ns2.dedikuotas.lt"]]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/webmail-geo/domains": {"get": {"tags": ["Webmail GEO"], "summary": "List webmail GEO domains", "description": "Your cPanel mail domains and their webmail login GEO-protection state.", "operationId": "webmail_geo_list", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"ApiKey": []}]}, "post": {"tags": ["Webmail GEO"], "summary": "Set webmail GEO for a domain", "description": "Enable/disable + configure webmail login GEO-restriction for one of your domains.", "operationId": "webmail_geo_set", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebmailGeoCfg"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/webmail-geo/domains/{domain_id}": {"delete": {"tags": ["Webmail GEO"], "summary": "Remove webmail GEO", "description": "Remove GEO protection from a domain.", "operationId": "webmail_geo_delete", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/webmail-geo/domains/{domain_id}/ip-rules": {"get": {"tags": ["Webmail GEO"], "summary": "List IP overrides", "operationId": "webmail_geo_ip_list", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["Webmail GEO"], "summary": "Add IP override", "description": "Add a per-domain IP allow (bypass GEO) or deny (always block).", "operationId": "webmail_geo_ip_add", "security": [{"ApiKey": []}], "parameters": [{"name": "domain_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Domain Id"}, "description": "Domain id (from GET /domains)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebmailGeoIp"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/webmail-geo/ip-rules/{rule_id}": {"delete": {"tags": ["Webmail GEO"], "summary": "Delete IP override", "operationId": "webmail_geo_ip_delete", "security": [{"ApiKey": []}], "parameters": [{"name": "rule_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Rule Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/webmail-geo/attempts": {"get": {"tags": ["Webmail GEO"], "summary": "Webmail login attempts", "description": "Webmail login attempts to your domains, with GEO/ASN, paginated.", "operationId": "webmail_geo_attempts", "security": [{"ApiKey": []}], "parameters": [{"name": "result", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Result"}}, {"name": "search", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Search"}, "description": "Free-text search across the description, action and category."}, {"name": "page", "in": "query", "required": false, "schema": {"type": "integer", "default": 1, "title": "Page"}, "description": "Page number, 1-based (default 1)."}, {"name": "per_page", "in": "query", "required": false, "schema": {"type": "integer", "default": 25, "title": "Per Page"}, "description": "Rows per page (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/webmail-geo/stats": {"get": {"tags": ["Webmail GEO"], "summary": "Webmail login stats", "operationId": "webmail_geo_stats", "security": [{"ApiKey": []}], "parameters": [{"name": "hours", "in": "query", "required": false, "schema": {"type": "integer", "default": 24, "title": "Hours"}, "description": "Look-back window in hours (1\u2013720)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/malware/services": {"get": {"tags": ["Malware"], "summary": "List scannable hosting services", "description": "Your cPanel hosting services that support malicious-code scanning, with each service's notification state.", "operationId": "malware_list_services", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"services": [{"service_id": 15231, "name": "cPanel hosting", "domain": "example.lt", "username": "exampl", "scanning_available": true, "notify_enabled": true}]}}}}}, "security": [{"ApiKey": []}]}}, "/v1/malware/services/{service_id}/scan": {"post": {"tags": ["Malware"], "summary": "Start a malicious-code scan", "description": "Queue a malicious-code scan for one domain. Rate-limited per domain; returns a `code`\n(queued | rate_limited | in_progress | not_available | no_username) and the `scan_id`.", "operationId": "malware_scan_start", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MalwareScanBody"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "code": "queued", "scan_id": 8841, "message": "Malware scan queued"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/malware/services/{service_id}/scan-status": {"get": {"tags": ["Malware"], "summary": "Latest scan status for a domain", "description": "Status of the most recent scan for a domain (pending | scanning | completed | failed | unknown).", "operationId": "malware_scan_status", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "domain", "in": "query", "required": true, "schema": {"type": "string", "title": "Domain"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"scan_id": 8841, "status": "completed", "domain": "example.lt", "malicious_count": 2, "total_files_scanned": 48213, "started_at": "2026-10-04T10:12:00Z", "completed_at": "2026-10-04T10:16:31Z", "error_message": null}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/malware/scans/{scan_id}": {"get": {"tags": ["Malware"], "summary": "Scan result with infected files", "description": "Full result of one scan, including the list of detected malicious files.", "operationId": "malware_scan_detail", "security": [{"ApiKey": []}], "parameters": [{"name": "scan_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Scan Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"scan_id": 8841, "domain": "example.lt", "status": "completed", "malicious_count": 2, "total_files_scanned": 48213, "scan_tool": "imunifyav", "created_at": "2026-10-04T10:12:00Z", "completed_at": "2026-10-04T10:16:31Z", "infected_files": [{"file_path": "/home/exampl/public_html/wp-content/uploads/x.php", "malware_type": "backdoor", "threat_name": "SMW-BKDR", "file_status": "found", "detected_at": "2026-10-04T10:16:00Z"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/malware/services/{service_id}/scan-history": {"get": {"tags": ["Malware"], "summary": "Recent scans for a service", "description": "Recent scans for a hosting service (newest first, up to `limit`, max 100).", "operationId": "malware_scan_history", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 20, "title": "Limit"}, "description": "Maximum rows to return (1\u2013200, default 50)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"history": [{"scan_id": 8841, "domain": "example.lt", "status": "completed", "malicious_count": 2, "total_files_scanned": 48213, "created_at": "2026-10-04T10:12:00Z", "completed_at": "2026-10-04T10:16:31Z"}]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/malware/services/{service_id}/notify": {"get": {"tags": ["Malware"], "summary": "Get scan-notification settings", "description": "Scheduled-scan notification settings for a hosting service (enabled, recipients, cadence/time, last run/report).", "operationId": "malware_notify_get", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"configured": true, "enabled": true, "has_account": true, "recipient_emails": ["me@example.lt", "dev@example.lt"], "cadence": "weekly", "hour": 3, "minute": 30, "day_of_week": 0, "day_of_month": 1, "owner_email": "me@example.lt", "next_run_at": "2026-10-06T00:30:00Z", "last_run_at": "2026-09-29T00:30:00Z", "last_status": "completed", "last_threats": 0, "last_report_sent_at": null}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Malware"], "summary": "Set scan-notification settings", "description": "Enable/disable scheduled scanning + email notifications and set recipients + schedule for a hosting service.", "operationId": "malware_notify_set", "security": [{"ApiKey": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Service Id"}, "description": "Service id of the VPS/VDS (from GET /vps) or Virtual Router (from GET /virtual-routers)."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MalwareNotifyBody"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}, "example": {"success": true, "enabled": true, "recipient_emails": ["me@example.lt", "dev@example.lt"]}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/ssl/preflight": {"post": {"tags": ["SSL"], "summary": "Preflight an SSL request", "description": "Check, at **zero cost and without touching Let's Encrypt**, how a certificate\nwould be issued for each domain: which validation method we would auto-pick (hosting\nAutoSSL, DNS-01, edge, or a delegated/HTTP-01 fallback), whether wildcards are\nsupported, and your remaining weekly issuance budget. Only domains you own are\naccepted. **Always preflight (or dry-run) before issuing.**", "operationId": "ssl_preflight", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslPreflightBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslPreflightResponse"}, "example": {"results": [{"domain": "example.lt", "chosen_method": "dns01", "reason": "Your DNS is managed with us \u2014 issuing via DNS validation (wildcard supported).", "alternatives": [], "wildcard_supported": true, "checks": {"owned": true, "hosted_with_us": false, "dns_managed_by_us": true, "caa_ok": true}, "action_required": null}, {"domain": "*.example.lt", "chosen_method": "dns01", "reason": "Wildcard certificate \u2014 issued via DNS validation (your DNS is managed with us).", "alternatives": [], "wildcard_supported": true, "checks": {"owned": true, "dns_managed_by_us": true, "caa_ok": true}, "action_required": null}], "budget": {"registered_domain": "example.lt", "remaining": 45, "limit": 45, "window_days": 7, "resets_at": "2026-10-06T00:00:00+00:00"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"ApiKey": []}]}}, "/v1/ssl/certificates": {"get": {"tags": ["SSL"], "summary": "List your certificates", "description": "List the managed certificates on your account (optionally filter by `domain`).", "operationId": "ssl_list_certificates", "security": [{"ApiKey": []}], "parameters": [{"name": "domain", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Domain"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/SslCertificateItem"}, "title": "Response Ssl List Certificates"}, "example": [{"id": 12, "domain": "example.lt", "sans": ["example.lt", "www.example.lt"], "method": "dns01", "install_target": "download", "status": "issued", "environment": "production", "key_custody": "customer_csr", "not_before": "2026-09-29T10:00:00+00:00", "not_after": "2026-12-28T10:00:00+00:00", "last_error_code": null, "created_at": "2026-09-29T10:00:00+00:00", "updated_at": "2026-09-29T10:01:00+00:00"}]}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["SSL"], "summary": "Issue a certificate", "description": "Issue a managed Let's Encrypt certificate for domains you own. We auto-pick the\nvalidation method (see `preflight`). `dry_run=true` runs against Let's Encrypt\n**staging** \u2014 it exercises the whole flow (real DNS challenge) but issues an\nuntrusted cert and consumes **no** production budget; always dry-run first. Issuance\nruns in the background: poll `GET /v1/ssl/certificates/{id}` for status.", "operationId": "ssl_issue", "security": [{"ApiKey": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslIssueBody"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslCertificateItem"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/ssl/budget": {"get": {"tags": ["SSL"], "summary": "Remaining SSL issuance budget", "description": "Remaining production issuances for a domain's registered-domain in the rolling\nweekly window. We refuse to exceed this **before** hitting Let's Encrypt's own limit.", "operationId": "ssl_budget", "security": [{"ApiKey": []}], "parameters": [{"name": "domain", "in": "query", "required": true, "schema": {"type": "string", "title": "Domain"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslBudget"}, "example": {"registered_domain": "example.lt", "remaining": 45, "limit": 45, "window_days": 7, "resets_at": "2026-10-06T00:00:00+00:00"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/ssl/certificates/{cert_id}": {"get": {"tags": ["SSL"], "summary": "Certificate status", "description": "Status/expiry of one certificate (poll after issuing).", "operationId": "ssl_get_certificate", "security": [{"ApiKey": []}], "parameters": [{"name": "cert_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Cert Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SslCertificateItem"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/v1/ssl/certificates/{cert_id}/download": {"get": {"tags": ["SSL"], "summary": "Download certificate", "description": "Download the issued certificate. `format=pem` returns the fullchain (and the private\nkey, if we hold it). `format=pfx` returns a base64 **PKCS#12 / .pfx** bundle for\nWindows / IIS (optional `password`) \u2014 available only when Servera holds the private key\n(i.e. you did not supply your own CSR).", "operationId": "ssl_download", "security": [{"ApiKey": []}], "parameters": [{"name": "cert_id", "in": "path", "required": true, "schema": {"type": "integer", "title": "Cert Id"}}, {"name": "format", "in": "query", "required": false, "schema": {"enum": ["pem", "pfx"], "type": "string", "default": "pem", "title": "Format"}}, {"name": "password", "in": "query", "required": false, "schema": {"type": "string", "default": "", "title": "Password"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}}, "components": {"schemas": {"AttachVm": {"properties": {"target_service_id": {"type": "integer", "title": "Target Service Id"}}, "type": "object", "required": ["target_service_id"], "title": "AttachVm"}, "Autoresponder": {"properties": {"email": {"type": "string", "title": "Email"}, "subject": {"type": "string", "title": "Subject"}, "body": {"type": "string", "title": "Body"}, "from_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "From Name"}, "interval": {"type": "integer", "title": "Interval", "default": 24}, "start_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Start At"}, "stop_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Stop At"}}, "type": "object", "required": ["email", "subject", "body"], "title": "Autoresponder"}, "BackupCreate": {"properties": {"mode": {"type": "string", "enum": ["snapshot", "suspend", "stop"], "title": "Mode", "default": "snapshot"}, "notes": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Notes"}}, "type": "object", "title": "BackupCreate"}, "ContactData": {"properties": {"first_name": {"type": "string", "title": "First Name"}, "last_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Name", "default": ""}, "company_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Name", "default": ""}, "company_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Code", "default": ""}, "email": {"type": "string", "title": "Email"}, "tax_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tax Id", "default": ""}, "phone": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Phone", "default": ""}, "address1": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Address1", "default": ""}, "address2": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Address2", "default": ""}, "city": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "City", "default": ""}, "state": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "State", "default": ""}, "postcode": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Postcode", "default": ""}, "country": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Country", "default": "LT"}, "general_emails": {"type": "boolean", "title": "General Emails", "default": true}, "invoice_emails": {"type": "boolean", "title": "Invoice Emails", "default": true}, "support_emails": {"type": "boolean", "title": "Support Emails", "default": true}, "product_emails": {"type": "boolean", "title": "Product Emails", "default": true}, "domain_emails": {"type": "boolean", "title": "Domain Emails", "default": true}, "affiliate_emails": {"type": "boolean", "title": "Affiliate Emails", "default": false}}, "type": "object", "required": ["first_name", "email"], "title": "ContactData"}, "DevTagsBody": {"properties": {"tags": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Tags", "description": "full replacement tag list (catalog slugs or custom text, max 40 chars each, max 30); omit to leave tags unchanged"}, "comment": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Comment", "description": "the free-text comment (max 4000 chars); empty string clears it"}, "set_comment": {"type": "boolean", "title": "Set Comment", "description": "set true to change the comment; sending a `comment` field also counts. A tags-only request never touches the comment.", "default": false}}, "type": "object", "title": "DevTagsBody"}, "DnsRecordCreate": {"properties": {"name": {"type": "string", "title": "Name", "description": "Record name/subdomain, or '@' for the apex. Letters, digits and '-', '_', '.', '*' only."}, "type": {"type": "string", "enum": ["A", "AAAA", "CNAME", "MX", "TXT", "SRV", "CAA"], "title": "Type"}, "content": {"type": "string", "title": "Content"}, "ttl": {"type": "integer", "title": "Ttl", "default": 3600}, "priority": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Priority"}}, "type": "object", "required": ["name", "type", "content"], "title": "DnsRecordCreate", "example": {"content": "185.209.139.4", "name": "api", "ttl": 3600, "type": "A"}}, "DnsRecordUpdate": {"properties": {"old_name": {"type": "string", "title": "Old Name"}, "old_type": {"type": "string", "title": "Old Type"}, "old_content": {"type": "string", "title": "Old Content"}, "new_name": {"type": "string", "title": "New Name"}, "new_type": {"type": "string", "enum": ["A", "AAAA", "CNAME", "MX", "TXT", "SRV", "CAA"], "title": "New Type"}, "new_content": {"type": "string", "title": "New Content"}, "ttl": {"type": "integer", "title": "Ttl", "default": 3600}, "priority": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Priority"}}, "type": "object", "required": ["old_name", "old_type", "old_content", "new_name", "new_type", "new_content"], "title": "DnsRecordUpdate"}, "EmailRef": {"properties": {"email": {"type": "string", "title": "Email"}}, "type": "object", "required": ["email"], "title": "EmailRef"}, "FirewallRule": {"properties": {"type": {"type": "string", "enum": ["in", "out"], "title": "Type"}, "action": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Action", "description": "ACCEPT, DROP, REJECT, TARPIT or LOG (case-insensitive)."}, "enable": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Enable", "default": 1}, "source": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Source", "description": "Source IP or CIDR (e.g. 1.2.3.4 or 10.0.0.0/8)."}, "dest": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dest", "description": "Destination IP or CIDR."}, "proto": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Proto", "description": "Protocol: tcp, udp, icmp, icmpv6, \u2026"}, "dport": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dport", "description": "Destination port, range N-M, or comma list; each \u226465535."}, "sport": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Sport", "description": "Source port, range N-M, or comma list; each \u226465535."}, "comment": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Comment"}, "iface": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Iface"}, "group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Group"}}, "type": "object", "required": ["type"], "title": "FirewallRule", "example": {"action": "ACCEPT", "comment": "HTTPS", "dport": "443", "proto": "tcp", "type": "in"}}, "FirewallRuleMove": {"properties": {"moveto": {"type": "integer", "title": "Moveto"}}, "type": "object", "required": ["moveto"], "title": "FirewallRuleMove"}, "FirewallToggle": {"properties": {"enabled": {"type": "boolean", "title": "Enabled"}}, "type": "object", "required": ["enabled"], "title": "FirewallToggle"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "InternalTraffic": {"properties": {"allow": {"type": "boolean", "title": "Allow"}}, "type": "object", "required": ["allow"], "title": "InternalTraffic"}, "MalwareNotifyBody": {"properties": {"enabled": {"type": "boolean", "title": "Enabled", "description": "Turn scheduled malicious-code scanning + email notifications on/off for this service.", "default": false}, "recipient_emails": {"items": {"type": "string"}, "type": "array", "title": "Recipient Emails", "description": "Who receives the report email. Max 20. You may include or omit the account owner."}, "cadence": {"type": "string", "title": "Cadence", "description": "How often to scan: daily | weekly | monthly.", "default": "daily"}, "hour": {"type": "integer", "maximum": 23.0, "minimum": 0.0, "title": "Hour", "description": "Hour of day (Europe/Vilnius).", "default": 4}, "minute": {"type": "integer", "maximum": 59.0, "minimum": 0.0, "title": "Minute", "description": "Minute of hour (Europe/Vilnius).", "default": 0}, "day_of_week": {"type": "integer", "maximum": 6.0, "minimum": 0.0, "title": "Day Of Week", "description": "Weekly cadence only: 0=Monday \u2026 6=Sunday.", "default": 0}, "day_of_month": {"type": "integer", "maximum": 28.0, "minimum": 1.0, "title": "Day Of Month", "description": "Monthly cadence only: day 1\u201328.", "default": 1}, "notify_on_clean": {"type": "boolean", "title": "Notify On Clean", "description": "Also email the report when a scan finds 0 malware (default: only email when threats are found).", "default": false}}, "type": "object", "title": "MalwareNotifyBody", "example": {"cadence": "weekly", "day_of_week": 0, "enabled": true, "hour": 3, "minute": 30, "notify_on_clean": false, "recipient_emails": ["me@example.lt", "dev@example.lt"]}}, "MalwareScanBody": {"properties": {"domain": {"type": "string", "title": "Domain", "description": "A domain on this hosting service to scan (its document root under public_html)."}}, "type": "object", "required": ["domain"], "title": "MalwareScanBody", "example": {"domain": "example.lt"}}, "OrderCreateBody": {"properties": {"items": {"items": {"$ref": "#/components/schemas/OrderItemModel"}, "type": "array", "title": "Items", "description": "One or more products to order."}}, "type": "object", "required": ["items"], "title": "OrderCreateBody", "example": {"items": [{"billing_cycle": "monthly", "config_options": {"3": {"value_id": 71}}, "datacenter": "lt", "hostname": "app.example.com", "product_id": 2629, "type": "product"}]}}, "OrderItemModel": {"properties": {"type": {"type": "string", "const": "product", "title": "Type", "description": "Item type. 'product' = a new VPS/VDS/hosting or other catalog product.", "default": "product"}, "product_id": {"type": "integer", "title": "Product Id", "description": "Product id (from GET /products)."}, "billing_cycle": {"type": "string", "title": "Billing Cycle", "description": "Billing cycle the product offers: monthly, quarterly, semiannually, annually, biennially or triennially."}, "quantity": {"type": "integer", "maximum": 20.0, "minimum": 1.0, "title": "Quantity", "description": "How many (default 1).", "default": 1}, "config_options": {"anyOf": [{"additionalProperties": true, "type": "object"}, {"type": "null"}], "title": "Config Options", "description": "Configurable options, shape {\"<option_id>\": {\"value_id\": <id>}} - e.g. the OS template."}, "hostname": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Hostname", "description": "Hostname/primary domain for cPanel or VPS products (e.g. 'app.example.com')."}, "datacenter": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Datacenter", "description": "Datacenter code, e.g. 'lt' or 'de'."}}, "type": "object", "required": ["product_id", "billing_cycle"], "title": "OrderItemModel"}, "OsTemplate": {"properties": {"id": {"type": "integer", "title": "Id"}, "label": {"type": "string", "title": "Label"}, "os_family": {"type": "string", "title": "Os Family"}, "icon_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Icon Url"}}, "type": "object", "required": ["id", "label", "os_family"], "title": "OsTemplate"}, "OsTemplateList": {"properties": {"templates": {"items": {"$ref": "#/components/schemas/OsTemplate"}, "type": "array", "title": "Templates"}, "type": {"type": "string", "title": "Type"}}, "type": "object", "required": ["templates", "type"], "title": "OsTemplateList", "example": {"templates": [{"icon_url": "/uploads/option-icons/value-21-\u2026.svg", "id": 101, "label": "AlmaLinux 8", "os_family": "linux"}, {"id": 102, "label": "AlmaLinux 9", "os_family": "linux"}, {"id": 118, "label": "Ubuntu 24.04", "os_family": "linux"}], "type": "qemu"}}, "PartnerBreakdownLine": {"properties": {"code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Code"}, "label": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Label"}, "amount": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Amount"}, "note": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Note"}}, "type": "object", "title": "PartnerBreakdownLine"}, "PartnerCancelResult": {"properties": {"order_number": {"type": "string", "title": "Order Number"}, "status": {"type": "string", "enum": ["pending", "active", "cancelled", "refunded"], "title": "Status", "default": "cancelled"}}, "type": "object", "required": ["order_number"], "title": "PartnerCancelResult"}, "PartnerCustomer": {"properties": {"email": {"type": "string", "title": "Email", "description": "End-customer email (used to create/identify the account)."}, "first_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "First Name"}, "last_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Name"}, "company_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Name"}, "company_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Number", "description": "Company registration code."}, "tax_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tax Id", "description": "VAT / tax id, e.g. LT100000000000."}, "phone": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Phone"}, "country": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Country", "description": "ISO country code, e.g. LT."}, "language": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Language", "description": "Preferred language, e.g. lt or en."}, "vat_validated": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Vat Validated", "description": "Set true if YOU (the partner) already validated this VAT number via VIES at registration. Servera then records the validation so the invoice applies 0% reverse charge for a valid intra-EU B2B customer (e.g. an LV company billed by the LT company). Send ONLY when the VIES check actually returned valid.", "default": false}, "vat_validated_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Vat Validated Name", "description": "Company name returned by VIES for that VAT number (optional; stored with the validation)."}}, "type": "object", "required": ["email"], "title": "PartnerCustomer"}, "PartnerCustomerInfo": {"properties": {"customer_id": {"type": "integer", "title": "Customer Id"}, "email": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Email"}, "company_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Name"}, "name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}, "country": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Country"}, "language": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Language"}, "email_verified": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Email Verified"}, "created_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Created At"}, "customer_created": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Customer Created", "description": "Only set by POST /partner/customers: true if a new account was created, false if an existing one was updated/reused."}, "services": {"items": {"$ref": "#/components/schemas/PartnerServiceInfo"}, "type": "array", "title": "Services", "default": []}}, "type": "object", "required": ["customer_id"], "title": "PartnerCustomerInfo"}, "PartnerCustomerPatch": {"properties": {"company_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Name"}, "company_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Company Number"}, "tax_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tax Id"}, "first_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "First Name"}, "last_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Name"}, "phone": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Phone"}, "address1": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Address1"}, "address2": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Address2"}, "city": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "City"}, "state": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "State"}, "postcode": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Postcode"}, "country": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Country"}, "language": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Language"}}, "type": "object", "title": "PartnerCustomerPatch", "description": "Requisite fields to update on an owned customer (only provided fields change).\nAffects FUTURE invoices only \u2014 issued invoices are snapshots.", "example": {"address1": "Vilniaus g. 1", "city": "Vilnius", "company_name": "UAB Pavyzdys", "company_number": "300123456", "country": "LT", "postcode": "01100", "tax_id": "LT100001112223"}}, "PartnerCustomerUpsertBody": {"properties": {"customer": {"$ref": "#/components/schemas/PartnerCustomer"}, "link_if_exists": {"type": "boolean", "title": "Link If Exists", "description": "If a customer with this email already exists in Servera but is not yet owned by this partner, adopt it and update its requisites instead of returning 409.", "default": false}, "send_emails": {"type": "boolean", "title": "Send Emails", "description": "Send the verification email when a NEW account is created.", "default": true}}, "type": "object", "required": ["customer"], "title": "PartnerCustomerUpsertBody", "example": {"customer": {"company_name": "UAB Pavyzdys", "company_number": "300000000", "country": "LT", "email": "klientas@pavyzdys.lt", "first_name": "Vardas", "language": "lt", "last_name": "Pavard\u0117", "tax_id": "LT100000000000"}, "link_if_exists": true}}, "PartnerItem": {"properties": {"product_id": {"type": "integer", "title": "Product Id", "description": "Allowed product id."}, "billing_cycle": {"type": "string", "title": "Billing Cycle", "description": "'onetime' for hardware, or monthly/quarterly/semiannually/annually/biennially/triennially for a subscription."}, "quantity": {"type": "integer", "maximum": 500.0, "minimum": 1.0, "title": "Quantity", "description": "How many.", "default": 1}, "giveaway": {"type": "boolean", "title": "Giveaway", "description": "If true, this line is a 100% giveaway (e.g. a free device bundled with a subscription): billed at full price with a -100% discount line on the invoice, netting to 0. The partner decides eligibility.", "default": false}, "giveaway_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Giveaway Name", "description": "Localized label for the giveaway discount line (e.g. 'Dovana - irenginys nemokamai'). Shown on the invoice. Defaults to a generic label when omitted."}}, "type": "object", "required": ["product_id", "billing_cycle"], "title": "PartnerItem"}, "PartnerOrderInfo": {"properties": {"order_id": {"type": "integer", "title": "Order Id"}, "order_number": {"type": "string", "title": "Order Number"}, "status": {"type": "string", "enum": ["pending", "active", "cancelled", "refunded"], "title": "Status"}, "total": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Total"}, "currency": {"type": "string", "title": "Currency", "default": "EUR"}, "created_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Created At"}, "invoice_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Invoice Id"}, "invoice_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Invoice Number"}, "invoice_status": {"anyOf": [{"type": "string"}, {"type": "null"}], "enum": ["unpaid", "paid", "cancelled", "draft", "refunded"], "title": "Invoice Status"}, "paid": {"type": "boolean", "title": "Paid", "default": false}, "payment_intent_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Payment Intent Id"}, "payment_pending": {"type": "boolean", "title": "Payment Pending", "default": false}}, "type": "object", "required": ["order_id", "order_number", "status"], "title": "PartnerOrderInfo"}, "PartnerOrderResult": {"properties": {"customer_id": {"type": "integer", "title": "Customer Id"}, "customer_created": {"type": "boolean", "title": "Customer Created", "default": false}, "order_id": {"type": "integer", "title": "Order Id"}, "order_number": {"type": "string", "title": "Order Number"}, "status": {"type": "string", "enum": ["pending", "active", "cancelled", "refunded"], "title": "Status"}, "invoice_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Invoice Id"}, "invoice_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Invoice Number"}, "total": {"type": "number", "title": "Total"}, "currency": {"type": "string", "title": "Currency", "default": "EUR"}, "pay_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Pay Url"}, "reference": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reference"}}, "type": "object", "required": ["customer_id", "order_id", "order_number", "status", "total"], "title": "PartnerOrderResult"}, "PartnerOrdersBody": {"properties": {"customer_id": {"type": "integer", "title": "Customer Id", "description": "Existing customer you own (from a prior provision response)."}, "items": {"items": {"$ref": "#/components/schemas/PartnerItem"}, "type": "array", "title": "Items", "description": "Products to order."}, "reference": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reference"}, "send_emails": {"type": "boolean", "title": "Send Emails", "default": true}, "start_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Start Date", "description": "Optional service start date (YYYY-MM-DD) for the whole order \u2014 recurring services are billed from this date instead of the payment date. Must be today or later. Omit to start from the payment date."}}, "type": "object", "required": ["customer_id", "items"], "title": "PartnerOrdersBody", "example": {"customer_id": 4790, "items": [{"billing_cycle": "onetime", "product_id": 2872, "quantity": 3}], "reference": "PO-2026-002", "send_emails": true, "start_date": "2026-09-27"}}, "PartnerPayBody": {"properties": {"payment_intent_id": {"type": "string", "title": "Payment Intent Id", "description": "The Stripe PaymentIntent id (pi_\u2026) returned by /pay-intent and confirmed on your page."}, "max_charge": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Max Charge", "description": "Optional cap; refused if the invoice total exceeds it."}}, "type": "object", "required": ["payment_intent_id"], "title": "PartnerPayBody", "example": {"max_charge": 3920.4, "payment_intent_id": "pi_3Qabc..."}}, "PartnerPayIntent": {"properties": {"payment_intent_id": {"type": "string", "title": "Payment Intent Id"}, "client_secret": {"type": "string", "title": "Client Secret"}, "publishable_key": {"type": "string", "title": "Publishable Key"}, "mode": {"type": "string", "enum": ["live", "test"], "title": "Mode", "description": "Environment this PaymentIntent was created in. Confirm it on your page with the matching Stripe.js publishable key (returned above).", "default": "live"}, "amount": {"type": "number", "title": "Amount"}, "currency": {"type": "string", "title": "Currency", "default": "EUR"}, "invoice_id": {"type": "integer", "title": "Invoice Id"}, "invoice_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Invoice Number"}}, "type": "object", "required": ["payment_intent_id", "client_secret", "publishable_key", "amount", "invoice_id"], "title": "PartnerPayIntent"}, "PartnerPayIntentBody": {"properties": {"mode": {"anyOf": [{"type": "string"}, {"type": "null"}], "enum": ["live", "test"], "title": "Mode", "description": "Processing environment: 'live' (default) or 'test'."}}, "type": "object", "title": "PartnerPayIntentBody", "description": "Optional body for POST \u2026/pay-intent. Use `mode` to choose the processing\nenvironment per call. Omit it (or send \"live\") for a real charge; send \"test\"\nto run a sandbox charge (test card, no real money) against the same order \u2014\nthe PaymentIntent is created with the matching key set and the order is pinned\nto that mode so the follow-up /pay (and any async confirmation) use it too.", "example": {"mode": "test"}}, "PartnerPayResult": {"properties": {"invoice_id": {"type": "integer", "title": "Invoice Id"}, "invoice_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Invoice Number"}, "document_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "enum": ["proforma", "vat"], "title": "Document Type"}, "converted_from_proforma": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Converted From Proforma"}, "status": {"type": "string", "enum": ["unpaid", "paid", "cancelled", "draft", "refunded"], "title": "Status"}, "is_paid": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Is Paid"}, "already_paid": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Already Paid"}, "method": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Method"}, "total": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Total"}, "net": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Net"}, "vat": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Vat"}, "vat_rate": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Vat Rate"}, "gross": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Gross"}, "currency": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Currency", "default": "EUR"}, "pending": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Pending"}, "payment_state": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Payment State"}, "note": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Note"}}, "type": "object", "required": ["invoice_id", "status"], "title": "PartnerPayResult"}, "PartnerProduct": {"properties": {"id": {"type": "integer", "title": "Id"}, "name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}, "name_en": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name En"}, "type": {"type": "string", "title": "Type"}, "currency": {"type": "string", "title": "Currency", "default": "EUR"}, "price": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Price"}, "billing_cycle": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Billing Cycle"}, "breakdown": {"anyOf": [{"items": {"$ref": "#/components/schemas/PartnerBreakdownLine"}, "type": "array"}, {"type": "null"}], "title": "Breakdown"}, "total_ex_vat": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Total Ex Vat"}, "pricing": {"anyOf": [{"additionalProperties": true, "type": "object"}, {"type": "null"}], "title": "Pricing"}, "split_per_cycle": {"anyOf": [{"additionalProperties": true, "type": "object"}, {"type": "null"}], "title": "Split Per Cycle"}, "component_labels": {"anyOf": [{"additionalProperties": true, "type": "object"}, {"type": "null"}], "title": "Component Labels"}}, "type": "object", "required": ["id", "type"], "title": "PartnerProduct"}, "PartnerProductsResult": {"properties": {"lang": {"type": "string", "title": "Lang"}, "products": {"items": {"$ref": "#/components/schemas/PartnerProduct"}, "type": "array", "title": "Products", "default": []}, "vat_rate": {"type": "number", "title": "Vat Rate", "default": 21.0}, "note": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Note"}}, "type": "object", "required": ["lang"], "title": "PartnerProductsResult"}, "PartnerProvisionBody": {"properties": {"customer": {"$ref": "#/components/schemas/PartnerCustomer"}, "items": {"items": {"$ref": "#/components/schemas/PartnerItem"}, "type": "array", "title": "Items", "description": "Products to order."}, "reference": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reference", "description": "Your own order reference (also used as idempotency anchor in notes)."}, "send_emails": {"type": "boolean", "title": "Send Emails", "description": "Send the end customer the verification + order emails.", "default": true}, "link_if_exists": {"type": "boolean", "title": "Link If Exists", "description": "If a customer with this email already exists in Servera but is not yet owned by this partner, link (adopt) it and place the order instead of returning 409. Use for returning customers who already have a Servera account.", "default": false}, "start_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Start Date", "description": "Optional service start date (YYYY-MM-DD) for the whole order. When set, recurring services are billed from this date (registration + next_due anchor here, and the invoice period shows [start_date, start_date+cycle)) instead of the payment date. Must be today or later. Omit to start billing from the payment date."}}, "type": "object", "required": ["customer", "items"], "title": "PartnerProvisionBody", "example": {"customer": {"company_name": "UAB Pavyzdys", "company_number": "300000000", "country": "LT", "email": "klientas@pavyzdys.lt", "first_name": "Vardas", "language": "lt", "last_name": "Pavard\u0117", "tax_id": "LT100000000000"}, "items": [{"billing_cycle": "onetime", "product_id": 2872, "quantity": 12}, {"billing_cycle": "annually", "product_id": 2877, "quantity": 12}], "reference": "PO-2026-001", "send_emails": true, "start_date": "2026-09-27"}}, "PartnerServiceInfo": {"properties": {"id": {"type": "integer", "title": "Id"}, "product_id": {"type": "integer", "title": "Product Id"}, "product_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Product Name"}, "status": {"type": "string", "enum": ["pending", "active", "suspended", "cancelled", "terminated", "completed"], "title": "Status"}, "billing_cycle": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Billing Cycle"}, "recurring_amount": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Recurring Amount", "description": "Recurring fee per cycle. null for one-time products (they have no recurring charge)."}, "next_due_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Next Due Date", "description": "Next billing date (end of the paid period). null for one-time products and for services not yet anchored."}, "registration_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Registration Date"}, "order_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Order Id", "description": "Id of the order that created this service."}, "order_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Order Number", "description": "Order number (ORD-\u2026) that created this service \u2014 use with order_item_index to link a service to its order line."}, "order_item_index": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Order Item Index", "description": "0-based position of this service's item within its order, stable across calls, so N services from quantity:N can be told apart."}}, "type": "object", "required": ["id", "product_id", "status"], "title": "PartnerServiceInfo"}, "PayInvoiceBody": {"properties": {"method": {"type": "string", "enum": ["credit", "bank_transfer", "spt"], "title": "Method", "description": "How to settle the invoice. `credit` = pay from your account balance, no browser step (returns 402 with the amount due if the balance doesn't cover the total). `bank_transfer` = leave the invoice unpaid and return a `pay_url` for a human to complete the payment in a browser. `spt` = charge a card with a Stripe Shared Payment Token supplied in `shared_payment_token` - a fully programmatic card payment for agents, no browser step. See `shared_payment_token` below.", "default": "credit"}, "shared_payment_token": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Shared Payment Token", "description": "A single-use Stripe Shared Payment Token (`spt_...`) - required when `method='spt'`, ignored otherwise. The buyer's agent obtains it from the buyer's payment provider, scoped to a specific amount and expiry; we charge that card directly and, on success, provision the same way as a credit payment. If the token's own limits are exceeded the charge is declined and the invoice stays unpaid."}}, "type": "object", "title": "PayInvoiceBody", "example": {"method": "credit"}}, "PowerRequest": {"properties": {"action": {"type": "string", "enum": ["start", "stop", "shutdown", "reboot"], "title": "Action"}}, "type": "object", "required": ["action"], "title": "PowerRequest", "example": {"action": "reboot"}}, "PublicIpMap": {"properties": {"private_ip": {"type": "string", "title": "Private Ip"}}, "type": "object", "required": ["private_ip"], "title": "PublicIpMap"}, "ReinstallRequest": {"properties": {"template_id": {"type": "integer", "title": "Template Id"}, "confirm": {"type": "boolean", "title": "Confirm", "default": false}}, "type": "object", "required": ["template_id"], "title": "ReinstallRequest", "example": {"confirm": true, "template_id": 102}}, "RuleMoveTo": {"properties": {"to": {"type": "integer", "title": "To"}}, "type": "object", "required": ["to"], "title": "RuleMoveTo"}, "SnapshotCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "vmstate": {"type": "boolean", "title": "Vmstate", "default": false}}, "type": "object", "required": ["name"], "title": "SnapshotCreate"}, "SslBudget": {"properties": {"registered_domain": {"type": "string", "title": "Registered Domain"}, "remaining": {"type": "integer", "title": "Remaining"}, "limit": {"type": "integer", "title": "Limit"}, "window_days": {"type": "integer", "title": "Window Days", "default": 7}, "resets_at": {"type": "string", "title": "Resets At"}}, "type": "object", "required": ["registered_domain", "remaining", "limit", "resets_at"], "title": "SslBudget"}, "SslCertificateItem": {"properties": {"id": {"type": "integer", "title": "Id"}, "domain": {"type": "string", "title": "Domain"}, "sans": {"items": {"type": "string"}, "type": "array", "title": "Sans", "default": []}, "method": {"type": "string", "title": "Method"}, "install_target": {"type": "string", "title": "Install Target"}, "status": {"type": "string", "title": "Status"}, "environment": {"type": "string", "title": "Environment"}, "key_custody": {"type": "string", "title": "Key Custody"}, "not_before": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Not Before"}, "not_after": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Not After"}, "last_error_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Error Code"}, "created_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["id", "domain", "method", "install_target", "status", "environment", "key_custody"], "title": "SslCertificateItem"}, "SslIssueBody": {"properties": {"domains": {"items": {"type": "string"}, "type": "array", "maxItems": 100, "minItems": 1, "title": "Domains", "description": "Domain(s) for the certificate. First is the primary CN; use *.example.com for a wildcard."}, "dry_run": {"type": "boolean", "title": "Dry Run", "description": "Run against Let's Encrypt STAGING (validates everything, consumes NO production budget). Always dry-run first.", "default": false}, "install_target": {"type": "string", "enum": ["auto", "download", "edge", "cpanel", "deploy_agent"], "title": "Install Target", "default": "auto"}, "csr": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Csr", "description": "Optional PEM CSR \u2014 keeps the private key on YOUR side (we never see it)."}}, "type": "object", "required": ["domains"], "title": "SslIssueBody", "example": {"domains": ["example.lt", "www.example.lt"], "dry_run": true, "install_target": "download"}}, "SslPreflightBody": {"properties": {"domains": {"items": {"type": "string"}, "type": "array", "maxItems": 100, "minItems": 1, "title": "Domains", "description": "Domain(s) to check. Use *.example.com for a wildcard."}}, "type": "object", "required": ["domains"], "title": "SslPreflightBody", "example": {"domains": ["example.lt", "*.example.lt"]}}, "SslPreflightResponse": {"properties": {"results": {"items": {"$ref": "#/components/schemas/SslPreflightResult"}, "type": "array", "title": "Results"}, "budget": {"$ref": "#/components/schemas/SslBudget"}}, "type": "object", "required": ["results", "budget"], "title": "SslPreflightResponse"}, "SslPreflightResult": {"properties": {"domain": {"type": "string", "title": "Domain"}, "chosen_method": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Chosen Method"}, "reason": {"type": "string", "title": "Reason"}, "error": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error"}, "alternatives": {"items": {"type": "string"}, "type": "array", "title": "Alternatives", "default": []}, "wildcard_supported": {"type": "boolean", "title": "Wildcard Supported", "default": false}, "checks": {"additionalProperties": true, "type": "object", "title": "Checks", "default": {}}, "action_required": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Action Required"}}, "type": "object", "required": ["domain", "reason"], "title": "SslPreflightResult"}, "TerminateBody": {"properties": {"mode": {"type": "string", "enum": ["immediate", "end_of_period", "scheduled"], "title": "Mode", "description": "immediate = destroy the VM now (backgrounded); end_of_period = cancel at the end of the paid billing period; scheduled = terminate on `scheduled_date`.", "default": "end_of_period"}, "scheduled_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Scheduled Date", "description": "YYYY-MM-DD; required when mode='scheduled'."}, "reason": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reason", "description": "Optional reason, stored with the request."}, "refund_as_credit": {"type": "boolean", "title": "Refund As Credit", "description": "If a refund applies, add it to the account credit balance instead of refunding the payment gateway.", "default": false}, "confirm": {"type": "boolean", "title": "Confirm", "description": "Must be true - termination is irreversible.", "default": false}}, "type": "object", "title": "TerminateBody", "example": {"confirm": true, "mode": "end_of_period"}}, "TicketCreate": {"properties": {"department_id": {"type": "integer", "title": "Department Id"}, "subject": {"type": "string", "title": "Subject"}, "message": {"type": "string", "title": "Message"}, "priority": {"type": "string", "enum": ["low", "medium", "high", "urgent"], "title": "Priority", "default": "medium"}, "related_service_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Related Service Id"}, "related_domain_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Related Domain Id"}}, "type": "object", "required": ["department_id", "subject", "message"], "title": "TicketCreate"}, "TicketReply": {"properties": {"message": {"type": "string", "title": "Message"}}, "type": "object", "required": ["message"], "title": "TicketReply"}, "TrustedSender": {"properties": {"server_id": {"type": "integer", "title": "Server Id"}, "cpanel_user": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Cpanel User"}, "sender": {"type": "string", "title": "Sender"}}, "type": "object", "required": ["server_id", "sender"], "title": "TrustedSender"}, "UnblockRequest": {"properties": {"ip": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Ip"}}, "type": "object", "title": "UnblockRequest"}, "UserInvite": {"properties": {"email": {"type": "string", "title": "Email"}, "permissions": {"items": {"type": "string"}, "type": "array", "title": "Permissions", "default": []}}, "type": "object", "required": ["email"], "title": "UserInvite"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "VpcFwOptions": {"properties": {"enable": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Enable"}, "policy_forward": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Policy Forward"}, "log_level_forward": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Log Level Forward"}}, "type": "object", "title": "VpcFwOptions"}, "VpcRule": {"properties": {"type": {"type": "string", "title": "Type"}, "action": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Action"}, "enable": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Enable", "default": 1}, "source": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Source"}, "dest": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dest"}, "proto": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Proto"}, "dport": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dport"}, "sport": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Sport"}, "comment": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Comment"}, "iface": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Iface"}, "macro": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Macro"}, "log": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Log"}}, "type": "object", "required": ["type"], "title": "VpcRule"}, "VpsSummary": {"properties": {"id": {"type": "integer", "title": "Id"}, "label": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Label"}, "status": {"type": "string", "title": "Status"}, "product_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Product Type"}, "ip_addresses": {"items": {"type": "string"}, "type": "array", "title": "Ip Addresses", "default": []}, "next_due_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Next Due Date"}}, "type": "object", "required": ["id", "status"], "title": "VpsSummary"}, "WafAdvanced": {"properties": {"bypass": {"items": {"type": "string"}, "type": "array", "title": "Bypass", "default": []}, "exclusions": {"items": {"additionalProperties": true, "type": "object"}, "type": "array", "title": "Exclusions", "default": []}}, "type": "object", "title": "WafAdvanced"}, "WafBindingCreate": {"properties": {"domain": {"type": "string", "title": "Domain"}}, "type": "object", "required": ["domain"], "title": "WafBindingCreate"}, "WafBotPolicy": {"properties": {"policy": {"additionalProperties": true, "type": "object", "title": "Policy"}}, "type": "object", "required": ["policy"], "title": "WafBotPolicy"}, "WafEnable": {"properties": {"reverse_proxy_host": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reverse Proxy Host"}}, "type": "object", "title": "WafEnable"}, "WafEngine": {"properties": {"enabled": {"type": "boolean", "title": "Enabled"}}, "type": "object", "required": ["enabled"], "title": "WafEngine"}, "WafListEntries": {"properties": {"entries": {"items": {}, "type": "array", "title": "Entries"}}, "type": "object", "required": ["entries"], "title": "WafListEntries"}, "WafPreset": {"properties": {"preset": {"type": "string", "title": "Preset"}, "disabled_components": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Disabled Components"}}, "type": "object", "required": ["preset"], "title": "WafPreset"}, "WebmailGeoCfg": {"properties": {"domain": {"type": "string", "title": "Domain", "description": "One of your cPanel mail domains."}, "enabled": {"type": "boolean", "title": "Enabled", "default": false}, "mode": {"type": "string", "title": "Mode", "description": "'whitelist' (allow only) or 'blacklist' (block).", "default": "whitelist"}, "countries": {"items": {"type": "string"}, "type": "array", "title": "Countries", "description": "ISO-2 country codes, e.g. ['LT','LV'].", "default": ["LT"]}, "fail_open": {"type": "boolean", "title": "Fail Open", "description": "Allow unknown/private IPs (recommended).", "default": true}}, "type": "object", "required": ["domain"], "title": "WebmailGeoCfg"}, "WebmailGeoIp": {"properties": {"ip_or_cidr": {"type": "string", "title": "Ip Or Cidr"}, "action": {"type": "string", "title": "Action", "description": "'allow' (bypass GEO) or 'deny' (always block) for this domain.", "default": "allow"}, "note": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Note"}}, "type": "object", "required": ["ip_or_cidr"], "title": "WebmailGeoIp"}, "WgPeer": {"properties": {"name": {"type": "string", "title": "Name", "default": "device"}, "public_key": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Public Key", "description": "Base64 WireGuard public key (44 chars, e.g. ends in '='). Omit to have a keypair generated and the config returned once. An invalid format is rejected with 400."}}, "type": "object", "title": "WgPeer"}, "WhitelistAdd": {"properties": {"ip": {"type": "string", "title": "Ip"}, "reason": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Reason"}}, "type": "object", "required": ["ip"], "title": "WhitelistAdd"}}, "securitySchemes": {"ApiKey": {"type": "http", "description": "Your `sk_live_\u2026` API key, sent as `Authorization: Bearer <key>`.", "scheme": "bearer"}}}, "tags": [{"name": "Meta", "description": "API status and the account your key belongs to."}, {"name": "VPS", "description": "Control your virtual servers - status, metrics, power, snapshots, backups, firewall, OS reinstall."}, {"name": "Billing", "description": "Invoices, invoice PDFs and your account balance."}, {"name": "Orders", "description": "List and inspect your orders."}, {"name": "Domains", "description": "Your domains and their DNS records (read and edit)."}, {"name": "SSL", "description": "Issue and manage Let's Encrypt certificates for your domains. We auto-detect the best validation method (hosting AutoSSL, DNS-01, or edge) and can install, return, or proxy the certificate. Free. Always preflight or dry-run first."}, {"name": "Tickets", "description": "Read, open and reply to support tickets."}, {"name": "Users", "description": "Account users - list, invite, resend invitations."}, {"name": "Emails", "description": "History of system emails sent to your account."}, {"name": "Mail", "description": "Email delivery & protection - delivery trace, RBL checks, whitelists, trusted senders, autoresponders."}, {"name": "Security", "description": "Shared-hosting IP blocks - check and self-unblock."}, {"name": "Networks", "description": "VPC networks and their firewall."}, {"name": "Virtual Router", "description": "Virtual Routers - WireGuard, public IPs, attached VMs."}, {"name": "WAF", "description": "Web Application Firewall - domains, presets, rules, lists, bot policy."}, {"name": "Malware", "description": "Malicious-code scanning for your cPanel hosting - start scans, read results, and schedule periodic scans with email notifications to you and extra contacts."}, {"name": "Contacts", "description": "Account contacts."}, {"name": "Tags", "description": "Organise your services and domains: assign tags (labels) from a predefined grouped catalog or your own custom text, and keep a free-text comment on each. The comment is visible to you and to Servera staff. Use tags:read / tags:write."}, {"name": "Logs", "description": "Your account activity log."}, {"name": "Partner Provisioning", "description": "Partner integration: create an end customer and place an order for partner-allowed products in one call. Requires the partner:provision scope."}]}