Skip to main content

API Changelog: User Panel Release 2.2

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

GET /team-billing/{team_id}/{start_date}/{end_date}/{interval}/{timezone}

GET /team-billing/{team_id}/{start_date}/{end_date}/{interval}?timezone=X

2

GET /team-billing/shared-storage/{team_id}/{start_date}/{end_date}/{interval}/{region_id}/{timezone}

GET /team-billing/shared-storage/{team_id}/{start_date}/{end_date}/{interval}?region_id=X&timezone=Y

3

GET /team-billing/gpuaas-pool/{team_id}/{start_date}/{end_date}/{interval}/{region_id}/{timezone}

GET /team-billing/gpuaas-pool/{team_id}/{start_date}/{end_date}/{interval}?region_id=X&timezone=Y

4

GET /workspace-billing/{workspace_id}/{start_date}/{end_date}/{interval}/{timezone}

GET /workspace-billing/{workspace_id}/{start_date}/{end_date}/{interval}?timezone=X

5

GET /team-billing/group-by-workspace/{team_id}/{start_date}/{end_date}/{interval}/{timezone}

GET /team-billing/group-by-workspace/{team_id}/{start_date}/{end_date}/{interval}?timezone=X

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

GET /service/i/details

GET /service/i/provisioning-info

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

GET /clusters

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: models.InstanceCreateOpts

Request body: models.UnifiedInstanceCreateOpts

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

DELETE /teams/{team_id} (plural)

DELETE /team/{team_id} (singular)

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

POST /policies/{policy_type} (plural)

POST /policy/{policy_type} (singular)

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

POST /instance/{instance_id}/add-disks (singular)

POST /instances/{instance_id}/add-disks (plural)

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

GET /gpuaas/{gpuaas_id}/pool-subscription

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

data_store_id

datastore_id

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

data

Removed

skip_gpu_pool

Removed

default

Added

is_quantity_locked

Added

max_quantity

Added

quantity

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

GET

/instances/unified

Paginated listing of unified instances (VMs + Pods combined). Supports filtering by team, workspace, status, region, image

GET

/instances/unified/{instance_id}

Get detailed info for a single unified instance

GET

/instances/unified/{instance_id}/exposed-services

Get exposed services for a pod instance (polling-optimized)

POST

/instances/unified/{instance_id}/retry

Retry a failed VM provisioning

POST

/instances/unified/{instance_id}/refresh-connections

Force-refresh connections for all pods in an instance

POST

/instances/unified/migrate-legacy-pods

Admin-only: start async migration of legacy pods to unified instances

GET

/instances/unified/migrate-legacy-pods/status

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

POST

/pods/volume-action

Mount/unmount pod volumes

GET

/pods/metrics

Get resource usage metrics for a pod

POST

/pods/{pod_id}/resize/instance-type

Resize pod to a different instance type

POST

/pods/{pod_id}/resize/ephemeral-storage

Resize pod ephemeral storage

GET

/pods/{pod_id}/resize/instance-type/options

Get available instance types for pod resize

GET

/pods/{pod_id}/resize/ephemeral-storage/options

Get available storage blocks for pod resize

GET

/pods/{pod_id}/resize/cost-estimate

Cost estimate for pod resize

Service Instance Provisioning (8 endpoints)

Method

Path

Description

GET

/service/i/team-accessible-scenarios

Scenarios accessible to a team

GET

/service/i/team-accessible-regions

Regions accessible to a team

GET

/service/i/scenario-compatible-services

Compatible services for a scenario and team

GET

/service/i/provisioning-info

Service provisioning details (replaces /service/i/details)

GET

/service/i/storage-blocks

Compatible storage blocks for a service

GET

/service/i/shared-volumes

Compatible shared volumes for a service

GET

/service/i/additional-disks

Compatible additional disks for a service

GET

/service/i/diagnose

Diagnose team service deployment eligibility

Service Options (5 endpoints)

Method

Path

Description

GET

/service/opts/images

Image options for a service

GET

/service/opts/instance-types

Instance type options for a service

GET

/service/opts/storage-blocks

Storage block options for a service

GET

/service/opts/accelerators

Accelerators grouped by vendor

POST

/service/opts/accelerator-pools

Accelerator pool options for a service

Service Management (3 endpoints)

Method

Path

Description

GET

/service/{service_id}/preview

Preview a service configuration

GET

/service/{service_id}/policies

Get policies linked to a service

GET

/service/{service_id}/instances

Get instances using a service

Service Images (1 endpoint — internal, no auth)

Method

Path

Description

GET

/service/image/{image_id}

Get a single service image (public, no auth required). Not documented in Swagger — internal/utility endpoint.

Instance Billing (1 endpoint)

Method

Path

Description

GET

/instance-billing/{instance_id}/{start_date}/{end_date}/{interval}

Get billing for a specific instance

Error Logging (1 endpoint — internal, no auth)

Method

Path

Description

POST

/error-log/log

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

/policy/defaults

Get default policy for each policy type

Instance Types (1 endpoint)

Method

Path

Description

GET

/instance-type/{instance_type_id}/storage-blocks/{storage_block_id}/assigned

Check if a storage block is assigned to an instance type

Removed Endpoints

#

Method

Path

Description

Replacement

1

GET

/clusters

Get active clusters

None (was admin-only, returned 403 for user panel)

2

GET

/service/{team_id}/health

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

models.UnifiedInstanceCreateOpts

12

Create options for unified instances

models.UnifiedInstanceListingResponse

12

Listing item for unified instances

models.UnifiedInstanceInfoResponse

19

Detailed info response

models.PaginatedUnifiedInstances

6

Paginated wrapper

models.UnifiedInstancePodInfo

6

Pod info within unified instance

models.UnifiedInstanceRegionInfo

11

Region details

models.UnifiedInstanceAcceleratorInfo

2

Accelerator summary

models.UnifiedInstanceDiskInfo

4

Disk info

models.UnifiedInstanceImageInfo

4

Image info

models.UnifiedInstanceServiceInfo

3

Service info

Service Provisioning Schemas

Schema

Fields

Description

models.ServiceProvisioningInfo

13

Replaces ServiceDetails

models.ServicePreview

27

Full service preview

models.ServiceOpts

14

Service creation/update options

models.ServiceDiagnosticResult

14

Diagnostic output

models.CompatibleServicesUnderScenarioResponse

3

Scenario-compatible services

Pod Resize Schemas

Schema

Fields

Description

models.ResizePodInstanceTypeRequest

1

Instance type resize request

models.ResizePodEphemeralStorageRequest

1

Storage resize request

models.PodResizeEstimateResponse

6

Cost estimate response

models.InstanceTypeResizeEstimate

6

Type resize cost

models.EphemeralStorageResizeEstimate

5

Storage resize cost

Diagnostic Schemas

Schema

Fields

Description

models.TeamDiagnosticResult

7

Team-level diagnostic

models.RegionDiagnostic

5

Region diagnostic

models.RGEligibilityDiagnostic

13

Resource group eligibility

models.DiagnosticCheck

6

Individual check result

models.DiagnosticReason

3

Reason for failure/warning

Removed Schemas (2)

Schema

Replacement

models.GPUModelDetails

Absorbed into new GPU compatibility schemas

models.ServiceDetails

Replaced by models.ServiceProvisioningInfo

Modified Schemas (14)

models.AddDiskRequest [BREAKING]

Change

Field

Removed

data_store_id

Added

datastore_id

models.DatastoreMiniJson [NON-BREAKING]

Change

Field

Added

disk_ids, max_vdisk_size, max_vdisk_size_redundant, total_mb, used_mb, virtupian_id

models.GPUDetails [BREAKING]

Change

Field

Removed

data, skip_gpu_pool

Added

default, is_quantity_locked, max_quantity, quantity

models.Image [NON-BREAKING]

Change

Field

Added

infiniband_support, max_driver_version, min_driver_version

models.ImageDetails [BREAKING]

Change

Field

Removed

data

Added

default

models.InstanceTypeDetails [BREAKING]

Change

Field

Removed

data

Added

default, gpu_scaling

models.Metrics [NON-BREAKING]

Change

Field

Added

pool_hours

models.Network [NON-BREAKING]

Change

Field

Added

is_dedicated, is_external_gateway, is_fault_tolerance, is_hidden, is_mgt, is_reserved, is_routable, is_vlan, is_vnc, is_wire_vlan, mac, nat_forwarding, physical_paths, vlan_tag, vnet_id

Removed

ip

models.PCIDev [NON-BREAKING]

Change

Field

Added

model_id, vendor_id

models.PodInfo [NON-BREAKING]

Change

Field

Added

gpu_count, services

models.PoolSubscriptionDetails [NON-BREAKING]

Change

Field

Added

infiniband_info

models.Region [NON-BREAKING]

Change

Field

Added

support_rdma

models.StorageBlockDetails [BREAKING]

Change

Field

Removed

data

Added

default, gpu_scaling

models.StorageBlockPricing [NON-BREAKING]

Change

Field

Added

currency, symbol

Auth and Middleware Changes

Rate Limiting — NEW [NON-BREAKING]

A global API rate limiter has been added:

Setting

Default

rate_limit_enabled

true

rate_limit_requests_per_minute

60

rate_limit_burst

10

  • 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

GET /api/service/image/{image_id}

Public service image access

POST /api/error-log/log

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

MySQLHost

string

127.0.0.1:3306

Configurable MySQL host

RateLimitEnabled

bool

true

Enable/disable rate limiting

RateLimitRequestsPerMinute

int

60

Rate limit per minute

RateLimitBurst

int

10

Rate limit burst size

Changed Defaults

Setting

Old Default

New Default

ClustersSyncPeriodInSeconds

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&region_id=r1 NEW: GET /api/service/i/provisioning-info?service_id=123&team_id=abc&region_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-subscription with GET /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.