Skip to main content

GPU Container

General conventions​

  • Base URL: https://api-neo.fpt.ai/
  • Path: api/bff/v1/gpucontainer/{orgIdentifier}/workspaces/{workspaceIdentifier}/{action}
  • Method: All endpoints use POST.
  • Service-specific headers: X-ENV: <APP_ENV>, X-Region: <region>
  • Common headers (apiClient): X-Org-Id, X-Workspace-Id, X-User-Id
  • Response: { "data": {...}, "errors": [] }

How to get token and headers​

  1. Log in to the Portal and navigate to the GPU Container page.
  2. Open the Network tab in browser DevTools, select the container.list request to get the API path format (including orgIdentifier and workspaceIdentifier).
  3. Copy the following request headers: cookie, x-env, x-org-id, x-region, x-user-id, x-workspace-id.

Endpoints​

#ActionQuery paramsBodyPurpose
1container.listname (search, optional){}List containers
2container.getcontainer_id{}Container details
3container.stat—{}Statistics by status
4container.create—See belowCreate a container
5container.startcontainer_id{ "action": "START" }Start
6container.stopcontainer_id{ "action": "STOP" }Stop
7container.restartcontainer_id{ "action": "RESTART" }Restart
8container.deletecontainer_id{}Delete
9container.editcontainer_idSee belowEdit settings / update whitelist
10container.downloadlogcontainer_id{}Download logs (responseType: blob)
11container.template.list—{}List templates
12container.template.configconfig_name{}Template configuration details
13container.flavor.list—{}List GPU flavors
14cost-estimation—See belowCost estimation

Request bodies​

4. container.create​

{
"name": "my-container",
"instance_type": "H100",
"container_group": "",
"purpose": "SERVICE",
"description": "",
"container_settings": [{
"enable_ssh": true,
"authorized_keys": [{ "name": "key1", "ssh_key": "ssh-ed25519 AAAA..." }],
"image_setting": { "image_url": "...", "image_tag": "latest", "image_user": "", "image_password": "", "fptcloud_official": false },
"volume_settings": [{ "volume_type": "TEMP_DISK | PERSISTENT_DISK", "mount_path": "/workspace", "mount_capacity": 100 }],
"advance_setting": {
"http_ports": [{ "container_port": 8888 }],
"tcp_ports": [{ "container_port": 22 }],
"container_envs": [{ "key": "K", "value": "V" }],
"startup_cmd": { "cmd": [], "args": [] },
"healthchecks": []
}
}],
"billing_plan": { "billing_type": "PAYG", "billing_level": "NORMAL", "cost_estimate": 0, "currency_code": "USD" }
}

Response: { id, name, status }.

9. container.edit​

Send back the full container object (retrieved from container.get) with your changes applied.

Top-level fields: id, status, created_at, updated_at, tenant_id, name, container_group, purpose, instance_type, billing_plan, description, tags, domain, version, deleted.

container_settings[] fields: enable_ssh, authorized_keys, ssh_connect, image_setting, volume_settings[{volume_name?, volume_type, mount_path, mount_capacity}], advance_setting{http_ports, tcp_ports, startup_cmd, container_envs, healthchecks, block_cidrs}.

To update the whitelist only:

{ "block_cidrs": [{ "type": "TCP | HTTP", "ports": [8888], "sources": ["1.2.3.4/32"], "description": "" }] }

14. cost-estimation​

{
"instance_type": "H100",
"container_settings": [{ "volume_settings": [{ "volume_type": "PERSISTENT_DISK", "mount_path": "/data", "mount_capacity": 100 }] }]
}

Response: { org_id, items: [{ sku, quantity, price }], currency_code, total }.

Responses​

ActionResponse
container.listdata: { items: ListItem[], total, page?, page_size?, total_pages? }; ListItem: id, name, status, region, org_id, ws_id, created_by, purpose, instance_type, container_group, tenant_id, container_settings[{image_setting, enable_ssh, authorized_keys, ssh_connect}], billing_plan, tags, created_at, updated_at
container.getSame as ListItem, but container_settings[] is fully populated: image_setting, enable_ssh, authorized_keys, ssh_connect, advance_setting, volume_settings, container_resource, observability.container_monitor{container_metric_url, container_log_url}
container.statdata: { stats: [{ status, count }] }
container.template.listdata: { items: [{ name, url, icon?, priority?, fptcloud_official? }], total, page?, size? }
container.template.config{ name, priority, fptcloud_official, purpose, flavor_name, description, instance_type, container_settings[{ image_settings, volume_settings, advanced_setting }] }
container.flavor.listdata: { items: [{ flavor, price_info{currency, value, unit?}, resource{cpu, ram, gpu, vram, temp_disk}, available, region }], total }

Enums​

  • status: CREATING, RUNNING, STOPPED, PROCESSING, FAILED, DELETING, DELETED
  • billing_type: PAYG, SAVING_PLAN_1_WEEK, SAVING_PLAN_1_MONTH, SAVING_PLAN_3_MONTH, SAVING_PLAN_1_YEAR
  • billing_level: NORMAL, WARNING, STOPPED, AT_RISK
  • volume_type: TEMP_DISK, PERSISTENT_DISK

Error codes​

Error format​

On error, HTTP status ≠ 2xx and the body has the following shape:

{ "code": "DDI-SYSTEM-00001", "message": "...", "params": {}, "role_based": false }
  • role_based: true — the error message depends on the caller's role (MANAGEMENT / WS_ADMIN / MEMBER).
  • HTTP 401 — the client logs out and redirects to the login page.

Common error codes (gateway / BFF / billing)​

CodeMeaning
INSUFFICIENT_BALANCEInsufficient credits. Role MANAGEMENT auto-opens the top-up modal; other roles are prompted to contact the owner.
INSUFFICIENT_PERMISSIONSThe caller does not have permission to perform this action.
EQ-RESOURCE-SYSTEM-LIMITResource quota reached (params.name).
BFF-CREATING-CONCURRENCYAnother resource is being created in this workspace/service. Wait for it to complete and try again.
route_not_foundEndpoint does not exist.
method_not_allowedWrong method. Only POST is accepted.
request_too_largeBody exceeds 64 KB.
invalid_tokenToken is invalid or expired.
gateway_internal_errorInternal gateway error.
upstream_unavailableBackend service is temporarily unavailable.
gateway_timeoutBackend service timed out.

GPU Container error codes​

CodeMessage
DDI-SYSTEM-00001The GPU Container service has not been configured for this tenant. Please contact support.
DDI-SYSTEM-00002An unknown error occurred. Please try again later.