API Changelog: User Panel — 2.1-release to 2.2
Summary
Metric | Count |
|---|---|
Total endpoints in oct-release | 65 (Swagger) / ~170 (actual routes) |
Total endpoints in titan | 274 (Swagger) |
Genuinely new endpoints | 35 |
Removed endpoints | 2 (1 deleted, 1 renamed) |
Modified endpoints (breaking) | 6 |
Modified endpoints (non-breaking) | 3 |
New schemas/DTOs | 223 |
Removed schemas/DTOs | 2 |
Modified schemas/DTOs | 14 |
Breaking changes | 7 |
Non-breaking changes | ~233+ |
Note: The oct-release Swagger spec only documented 65 endpoints, while ~170 routes existed in code. The titan release added comprehensive Swagger annotations across the entire API. This changelog focuses on actual route/behavior changes rather than documentation-only additions.
Breaking Changes
1. [BREAKING] Billing endpoints — timezone and region_id moved from path to query parameters
All billing endpoints had their URL structure changed. Path parameters timezone and region_id were removed from the URL and made optional query parameters.
# | Old URL (oct-release) | New URL (titan) |
|---|---|---|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
Impact: All clients calling billing endpoints with timezone/region_id in the URL path will get 404 errors.
Migration: Move timezone and region_id to query parameters. Both are now optional.
2. [BREAKING] /service/i/details renamed to /service/i/provisioning-info
Before | After |
|---|---|
|
|
The handler was renamed from GetServiceDetails to GetServiceProvisioningInfo. The response schema changed from models.ServiceDetails to models.ServiceProvisioningInfo.
Impact: Clients calling GET /service/i/details will get 404.
Migration: Update URL to /service/i/provisioning-info and adapt to the new response schema ServiceProvisioningInfo (13 fields).
3. [BREAKING] /clusters endpoint removed
Before | After |
|---|---|
| Removed |
The entire clusters.go controller was deleted. Note: the old endpoint already returned 403 Forbidden for non-admin users.
Impact: Any client calling GET /clusters will get 404.
Migration: Use the admin panel API if cluster information is needed, or use GET /regions for region-level data.
4. [BREAKING] POST /calcualate-instance-billing-estimate — request body schema changed
Before | After |
|---|---|
Request body: | Request body: |
models.UnifiedInstanceCreateOpts schema (12 fields):
{ "accelerator_pool_id": "integer", "additional_disk_ids": ["integer"], "image_id": "integer", "instance_count": "integer", "instance_name": "string", "instance_type_id": "integer", "network_id": "integer", "pod_opts": { "ephemeral_storage_block_id": "int", "gpu_count": "int", "shared_volume_ids": ["int"] }, "region_id": "string", "service_id": "integer", "ssh_key_ids": ["integer"], "vm_opts": { "datastore_id": "string", "password": "string", "resource_group_id": "string", "storage_block_id": "int", "username": "string" } }
Impact: Clients sending the old InstanceCreateOpts body will fail validation.
Migration: Restructure request body to use UnifiedInstanceCreateOpts. VM-specific and Pod-specific fields are now nested under vm_opts and pod_opts respectively.
5. [BACKWARD-COMPATIBLE] DELETE /teams/{team_id} path changed to DELETE /team/{team_id}
Before | After |
|---|---|
|
|
The old route DELETE /teams/{team_id} is preserved as a backward-compatible alias pointing to the same handler. Both old and new routes work. Only the new canonical route is documented in Swagger. Migration to the new route is recommended but not required.
6. [BACKWARD-COMPATIBLE] POST /policies/{policy_type} path changed to POST /policy/{policy_type}
Before | After |
|---|---|
|
|
The old route POST /policies/{policy_type} is preserved as a backward-compatible alias pointing to the same handler. Both old and new routes work. Only the new canonical route is documented in Swagger. Migration to the new route is recommended but not required.
7. [BACKWARD-COMPATIBLE] POST /instance/{instance_id}/add-disks path changed to POST /instances/{instance_id}/add-disks
Before | After |
|---|---|
|
|
The old route POST /instance/{instance_id}/add-disks is preserved as a backward-compatible alias pointing to the same handler. Both old and new routes work. Only the new canonical route is documented in Swagger. Migration to the new route is recommended but not required.
8. [BREAKING] GET /gpuaas/{gpuaas_id}/pool-subscription removed
Before | After |
|---|---|
| Removed from Swagger |
Migration: Use GET /gpuaas/pool-subscription with query parameters gpuaas_id and team_id instead.
9. [BREAKING] models.AddDiskRequest — field renamed
Before | After |
|---|---|
|
|
Impact: Clients sending data_store_id in add-disk requests will have the field ignored.
Migration: Rename field from data_store_id to datastore_id in request payloads.
10. [BREAKING] models.GPUDetails — fields removed and added
Field | Change |
|---|---|
| Removed |
| Removed |
| Added |
| Added |
| Added |
| Added |
Impact: Clients relying on data or skip_gpu_pool fields will break.
New Endpoints
Unified Instances (7 endpoints) — Major new feature
The unified instances API provides a single abstraction over VMs and Pods.
Method | Path | Description |
|---|---|---|
|
| Paginated listing of unified instances (VMs + Pods combined). Supports filtering by team, workspace, status, region, image |
|
| Get detailed info for a single unified instance |
|
| Get exposed services for a pod instance (polling-optimized) |
|
| Retry a failed VM provisioning |
|
| Force-refresh connections for all pods in an instance |
|
| Admin-only: start async migration of legacy pods to unified instances |
|
| Admin-only: check migration progress |
Response schema (listing): models.PaginatedUnifiedInstances containing models.UnifiedInstanceListingResponse (12 fields: id, name, status, nature, region, team, workspace, service, accelerator, image, instance_type, pods).
Pod Enhancements (7 endpoints)
Method | Path | Description |
|---|---|---|
|
| Mount/unmount pod volumes |
|
| Get resource usage metrics for a pod |
|
| Resize pod to a different instance type |
|
| Resize pod ephemeral storage |
|
| Get available instance types for pod resize |
|
| Get available storage blocks for pod resize |
|
| Cost estimate for pod resize |
Service Instance Provisioning (8 endpoints)
Method | Path | Description |
|---|---|---|
|
| Scenarios accessible to a team |
|
| Regions accessible to a team |
|
| Compatible services for a scenario and team |
|
| Service provisioning details (replaces /service/i/details) |
|
| Compatible storage blocks for a service |
|
| Compatible shared volumes for a service |
|
| Compatible additional disks for a service |
|
| Diagnose team service deployment eligibility |
Service Options (5 endpoints)
Method | Path | Description |
|---|---|---|
|
| Image options for a service |
|
| Instance type options for a service |
|
| Storage block options for a service |
|
| Accelerators grouped by vendor |
|
| Accelerator pool options for a service |
Service Management (3 endpoints)
Method | Path | Description |
|---|---|---|
|
| Preview a service configuration |
|
| Get policies linked to a service |
|
| Get instances using a service |
Service Images (1 endpoint — internal, no auth)
Method | Path | Description |
|---|---|---|
|
| Get a single service image (public, no auth required). Not documented in Swagger — internal/utility endpoint. |
Instance Billing (1 endpoint)
Method | Path | Description |
|---|---|---|
|
| Get billing for a specific instance |
Error Logging (1 endpoint — internal, no auth)
Method | Path | Description |
|---|---|---|
|
| Log application errors from frontend. No authentication required. Not documented in Swagger — internal/utility endpoint. |
Request body: ctrls.ErrorLogRequest (13 fields: message, stack, url, user_agent, timestamp, level, component, action, metadata, user_id, team_id, session_id, environment)
Policies (1 endpoint)
Method | Path | Description |
|---|---|---|
|
| Get default policy for each policy type |
Instance Types (1 endpoint)
Method | Path | Description |
|---|---|---|
|
| Check if a storage block is assigned to an instance type |
Removed Endpoints
# | Method | Path | Description | Replacement |
|---|---|---|---|---|
1 |
|
| Get active clusters | None (was admin-only, returned 403 for user panel) |
2 |
|
| Get service health for team | Commented out, no replacement |
Modified Endpoints
Billing Endpoints — Parameter Migration [BREAKING]
See Breaking Changes #1 above. All 5 billing endpoints had timezone and region_id moved from path to query parameters.
GET /cluster/{id}/resource-groups [NON-BREAKING]
Added optional query parameter: detailed (bool) — When true, includes detailed datastore information (disk IDs, storage metrics, vDisk size limits).
GET /pci-devs/all-cards/{region_id} [NON-BREAKING]
Now returns 404 (instead of empty array) when no PCI cards are found in the specified region.
GPUaaS Endpoints — Swagger Type Corrections [NON-BREAKING]
Multiple GPUaaS endpoints had swagger annotations corrected:
team_id parameter type: models.GetUUIDQueryParam changed to string
gpuaas_id parameter type: models.GetIntQueryParam changed to int/string
Error response type: utils.HttpError changed to utils.ErrorJson
These are documentation corrections; the actual runtime behavior is unchanged.
Schema/DTO Changes
New Schemas (223 total)
Key new schema groups:
Unified Instance Schemas
Schema | Fields | Description |
|---|---|---|
| 12 | Create options for unified instances |
| 12 | Listing item for unified instances |
| 19 | Detailed info response |
| 6 | Paginated wrapper |
| 6 | Pod info within unified instance |
| 11 | Region details |
| 2 | Accelerator summary |
| 4 | Disk info |
| 4 | Image info |
| 3 | Service info |
Service Provisioning Schemas
Schema | Fields | Description |
|---|---|---|
| 13 | Replaces ServiceDetails |
| 27 | Full service preview |
| 14 | Service creation/update options |
| 14 | Diagnostic output |
| 3 | Scenario-compatible services |
Pod Resize Schemas
Schema | Fields | Description |
|---|---|---|
| 1 | Instance type resize request |
| 1 | Storage resize request |
| 6 | Cost estimate response |
| 6 | Type resize cost |
| 5 | Storage resize cost |
Diagnostic Schemas
Schema | Fields | Description |
|---|---|---|
| 7 | Team-level diagnostic |
| 5 | Region diagnostic |
| 13 | Resource group eligibility |
| 6 | Individual check result |
| 3 | Reason for failure/warning |
Removed Schemas (2)
Schema | Replacement |
|---|---|
| Absorbed into new GPU compatibility schemas |
| Replaced by models.ServiceProvisioningInfo |
Modified Schemas (14)
models.AddDiskRequest [BREAKING]
Change | Field |
|---|---|
Removed |
|
Added |
|
models.DatastoreMiniJson [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.GPUDetails [BREAKING]
Change | Field |
|---|---|
Removed |
|
Added |
|
models.Image [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.ImageDetails [BREAKING]
Change | Field |
|---|---|
Removed |
|
Added |
|
models.InstanceTypeDetails [BREAKING]
Change | Field |
|---|---|
Removed |
|
Added |
|
models.Metrics [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.Network [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
Removed |
|
models.PCIDev [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.PodInfo [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.PoolSubscriptionDetails [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.Region [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
models.StorageBlockDetails [BREAKING]
Change | Field |
|---|---|
Removed |
|
Added |
|
models.StorageBlockPricing [NON-BREAKING]
Change | Field |
|---|---|
Added |
|
Auth and Middleware Changes
Rate Limiting — NEW [NON-BREAKING]
A global API rate limiter has been added:
Setting | Default |
|---|---|
|
|
|
|
|
|
Uses token-bucket algorithm, per user ID (authenticated) or per IP (unauthenticated)
Full administrators are exempt from rate limiting
Returns HTTP 429 Too Many Requests with error code ERR_RATE_LIMIT_EXCEEDED_CODE
In-memory cache with 5-minute expiration
Public (No-Auth) Endpoints
The following endpoints do not require authentication and are not documented in Swagger:
Endpoint | Purpose |
|---|---|
| Public service image access |
| Frontend error logging |
RBAC Changes
Several RBAC helper functions (checkTeamPermissions, checkRolePermissions, matchPermission, generateCacheKeyWithTeam) have been commented out, indicating a simplification of permission checking logic.
Infrastructure and Configuration Changes
New Configuration Fields
Field | Type | Default | Description |
|---|---|---|---|
| string |
| Configurable MySQL host |
| bool |
| Enable/disable rate limiting |
| int |
| Rate limit per minute |
| int |
| Rate limit burst size |
Changed Defaults
Setting | Old Default | New Default |
|---|---|---|
| 50 | 120 |
Error Code Changes
150+ error message constants were normalized to lowercase. If any client-side logic parses error messages by string matching, this will break.
New error code categories added:
Rate limiting: ERR_RATE_LIMIT_EXCEEDED_CODE
Pod operations: ERR_FAILED_TO_PROVISION_POD_CODE, ERR_FAILED_TO_DEPROVISION_POD_CODE, etc.
Service provisioning: 20+ new codes
Unified instances: ERR_FAILED_TO_RETREIVE_INSTANCES_CODE, etc.
Legacy pod migration: ERR_POD_MIGRATION_ALREADY_IN_PROGRESS_CODE, etc.
Startup Changes
Intent Recovery: At startup, ReconcileStaleIntents() runs to recover in-flight operations interrupted by service restart
Legacy Pod Migration: UpgradeMigrationRunLegacyPods() runs automatically at startup
Initialization: init() refactored to explicit InitConfiguration(), InitKeycloack(), InitDb(), InitModels(), InitializeMailer() calls
Cross-Cutting Code Quality
All json.Marshal calls now properly handle errors (previously
b, _ := json.Marshal(...))interface{} replaced with Go 1.18+ any type alias throughout
Comprehensive Swagger annotations added to all endpoints
Migration Guide
Step 1: Update Billing Endpoint URLs
Before:
GET /api/team-billing/{team_id}/2024-01-01/2024-01-31/daily/UTC GET /api/team-billing/shared-storage/{team_id}/2024-01-01/2024-01-31/daily/region-1/UTC
After:
GET /api/team-billing/{team_id}/2024-01-01/2024-01-31/daily?timezone=UTC GET /api/team-billing/shared-storage/{team_id}/2024-01-01/2024-01-31/daily?region_id=region-1&timezone=UTC
Apply this pattern to all 5 billing endpoints.
Step 2: Rename /service/i/details to /service/i/provisioning-info
OLD: GET /api/service/i/details?service_id=123&team_id=abc®ion_id=r1 NEW: GET /api/service/i/provisioning-info?service_id=123&team_id=abc®ion_id=r1
Update response parsing to use ServiceProvisioningInfo schema.
Step 3: Fix Pluralization Changes (Optional — old routes still work)
The following old routes have backward-compatible aliases and will continue to work, but migration to the new canonical routes is recommended:
OLD: DELETE /api/teams/{team_id} -> NEW: DELETE /api/team/{team_id} (both work) OLD: POST /api/policies/{policy_type} -> NEW: POST /api/policy/{policy_type} (both work) OLD: POST /api/instance/{id}/add-disks -> NEW: POST /api/instances/{id}/add-disks (both work)
Step 4: Update AddDiskRequest Field Name
{ "datastore_id": "ds-123", "disks": [] }
Step 5: Update Instance Billing Estimate Request Body
Restructure from flat InstanceCreateOpts to nested UnifiedInstanceCreateOpts:
Before:
{ "service_id": 1, "image_id": 2, "instance_type_id": 3, "storage_block_id": 4, "region_id": "r1", "datastore_id": "ds1" }
After:
{ "service_id": 1, "image_id": 2, "instance_type_id": 3, "region_id": "r1", "instance_name": "my-instance", "instance_count": 1, "vm_opts": { "storage_block_id": 4, "datastore_id": "ds1", "username": "user", "password": "pass", "resource_group_id": "rg1" }, "pod_opts": null }
Step 6: Update GPUDetails Response Parsing
{ "default": true, "is_quantity_locked": false, "max_quantity": 8, "quantity": 4, "id": 1, "name": "A100" }
Fields removed: data, skip_gpu_pool. Fields added: default, is_quantity_locked, max_quantity, quantity.
Step 7: Handle Rate Limiting
Add HTTP 429 handling to all API clients:
HTTP/1.1 429 Too Many Requests {"error_code": "ERR_RATE_LIMIT_EXCEEDED_CODE", "message": "rate limit exceeded"}
Implement exponential backoff or respect the rate limit of 60 requests/minute with burst of 10.
Step 8: Adopt Unified Instances API (Optional)
For new integrations, prefer the unified instances API over separate VM/Pod endpoints:
GET /api/instances/unified -> List all instances (VMs + Pods) GET /api/instances/unified/{id} -> Get instance details
Step 9: Update Error Message Parsing
If your client matches error messages by string, note that all error messages have been normalized to lowercase. Update any string comparisons accordingly.
Step 10: Remove References to Deleted Endpoints
Remove calls to
GET /clusters(was admin-only anyway)Remove calls to
GET /service/{team_id}/health(commented out)Replace
GET /gpuaas/{gpuaas_id}/pool-subscriptionwithGET /gpuaas/pool-subscription?gpuaas_id=X&team_id=Y
Verification Checklist
All 65 old Swagger endpoints accounted for (55 common + 10 removed/changed)
All 274 new Swagger endpoints documented
35 genuinely new routes identified via main.go diff
7 breaking changes confirmed (3 path changes are backward-compatible)
All breaking changes covered in migration guide
Schema/DTO changes enumerated (223 new, 2 removed, 14 modified)
Auth changes documented (rate limiting, public endpoints, RBAC)
Configuration changes documented
Generated on 2026-02-25. Source: git diff oct-release..titan in hostedai-user repository.