Download OpenAPI specification:Download
Management API for the GreenNode AI Platform — manage API keys, enable models, track spend, and configure rate limits and guardrails.
This document covers the management API only. Calling a model is out of scope here.
Authentication. All endpoints use the standard VNG Cloud OAuth2 flow. See the Authorization section
on the API documentation home page: obtain a client ID and client secret
from VNG Cloud IAM, exchange them at the authorization server for an access_token, then send
Authorization: Bearer <access_token> with every request.
Versions in the path. Endpoints live under both /v1 and /v2. Use exactly the path shown in this
document for each operation — it is the officially supported one. Some operations also exist on an older
version and behave identically, but others exist on one version only, so swapping v1 for v2 (or the
reverse) on the same path may return 404. When a version is superseded, this document is updated first.
Resource identifiers. Endpoints taking {apiKeyName} accept either the key id or the key name.
Prefer the id (auth-<uuid>, from GET /v1/api-keys): it does not change when a key is renamed.
{modelUuid}, {guardrailsId} and {rateLimitConfigId} accept ids only.
API key type. Every API key created through this document is of the same type and the type field always
returns normal. If your account holds a key issued by a service plan, these endpoints return 403 for that
key — contact support.
Token-credit. The AI Platform uses its own credit unit called a token-credit, at a rate of
1 token-credit = 1 credit (the GreenNode account credit). GET /v1/user-credit returns the granted and
consumed amounts for your account.
Conventions. Timestamps sent in a request body are epoch milliseconds; timestamps returned are
ISO-8601 with a +07:00 offset, for example 2026-10-01T10:12:44.000+07:00. In Cost & usage and Log,
multi-value filters (modelUuids, apiKeyIds, providers) are comma-separated strings; everywhere else
they are JSON arrays — check the schema of each endpoint. Creating or deleting an API key and enabling or
disabling a model are asynchronous: the response returns before the work is finished, so read the resource
back to confirm.
Errors. Every error response has the shape {"message": "..."}. For status 500 the message is always the
literal Internal Server Error. One inconsistency to be aware of: the API Keys and Models groups return
400 when a resource is not found, while Rate limit and Guardrails return 404 — handle both.
Creates a new API key. The call is asynchronous — the response returns immediately with status CREATING.
A key takes tens of seconds to a few minutes to become usable (up to ~5 minutes under heavy load).
Only one key operation runs at a time: if another key is CREATING or DELETING, the request is rejected. Create keys one after another.
To know when the key is ready: poll GET /v1/api-keys/{apiKeyName} every 5-10 seconds (allow at least a 10-minute timeout) until status is ACTIVE (ready) or ERROR (failed — delete that key and create a new one; keys in ERROR do not count towards your quota).
Once the key is ACTIVE, enable models for your account with POST /v2/models/user-settings before calling any model.
| name required | string [ 5 .. 35 ] characters ^[a-z0-9][a-z0-9\-]{3,33}[a-z0-9]$ 5-35 characters: lowercase a-z, digits 0-9 and hyphens only. It must NOT start or end with a hyphen. Uppercase letters, spaces and accented characters are rejected |
{- "name": "my-service-key"
}{- "data": {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key",
- "gatewayId": "gw-maas",
- "isDefault": null,
- "key": "<full key value>",
- "status": "CREATING",
- "actions": null,
- "models": null,
- "createdAt": "2026-10-01T10:12:44.000+07:00",
- "hasRateLimit": null,
- "type": "normal"
}
}Each entry accepts a key id or a key name.
| apiKeyNames required | Array of strings non-empty Key ids (recommended) or key names. Obtain from |
{- "apiKeyNames": [
- "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "auth-3cb5668a-a19f-4f0b-a963-6cd0c648ea04"
]
}{- "message": "API key name already exists."
}Accepts either the key id (auth-<uuid>) or the display name. Deletion is asynchronous — the key moves to DELETING and then disappears from the list.
| apiKeyName required | string Example: auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3 Key id (recommended) or key name. Get the id from |
const request = require('request'); const options = { method: 'DELETE', url: 'https://aiplatform-hcm.api.vngcloud.vn/v2/api-keys/%7BapiKeyName%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "message": "API key name already exists."
}Returns the API keys of your account, with pagination and filtering.
| page | integer Example: page=1 Page number, starting at 1. Pagination only applies when BOTH |
| size | integer Example: size=20 Items per page. Must be sent together with |
| name | string Example: name=my- Filter by key name — SUBSTRING match anywhere in the name, case-insensitive |
| from | string <date-time> Example: from=2026-10-01T00:00:00Z Start of range, ISO-8601 in UTC ending with |
| to | string <date-time> Example: to=2026-11-01T00:00:00Z End of range, ISO-8601 in UTC ending with |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/api-keys', qs: { page: '1', size: '20', name: 'my-', from: '2026-10-01T00:00:00Z', to: '2026-11-01T00:00:00Z' } }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "listData": [
- {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key",
- "gatewayId": "gw-maas",
- "isDefault": false,
- "key": "<full key value>",
- "status": "ACTIVE",
- "actions": null,
- "models": null,
- "createdAt": "2026-10-01T10:12:44.000+07:00",
- "hasRateLimit": true,
- "type": "normal"
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}Status, creation time and the models the key may call.
| apiKeyName required | string Example: auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3 Key id (recommended) or key name. Get the id from |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/api-keys/%7BapiKeyName%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key",
- "gatewayId": "gw-maas",
- "isDefault": false,
- "key": "<full key value>",
- "status": "ACTIVE",
- "actions": null,
- "models": null,
- "createdAt": "2026-10-01T10:12:44.000+07:00",
- "type": "normal"
}
}The rate-limit config currently applied to this key. If no rate-limit is attached, the response is {"data": null} with status 200.
| apiKeyName required | string Example: auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3 Key id (recommended) or key name. Get the id from |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/api-keys/%7BapiKeyName%7D/rate-limit-config' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "id": "a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512",
- "name": "team-a-limit",
- "status": "ACTIVE",
- "requests": true,
- "requestsLimit": 1000,
- "requestsTimeUnit": "minute",
- "requestsWindowType": "fixed",
- "tokens": true,
- "tokensLimit": 2000000,
- "tokensTimeUnit": "minute",
- "tokensWindowType": "fixed",
- "requestsTimeValue": 1,
- "tokensTimeValue": 1,
- "createdAt": "2026-10-05T15:30:00.000+07:00",
- "associatedModels": [
- {
- "models": [
- {
- "id": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT"
}
]
}
], - "associatedApiKeys": [
- {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key"
}
]
}
}Models available to your account, including whether each one is enabled.
| page | integer Example: page=1 Page number, starting at 1. Pagination only applies when BOTH |
| size | integer Example: size=20 Items per page. Must be sent together with |
| status | string Enum: "enabled" "disabled" Example: status=enabled Filter by enabled state for your account |
| name | string Example: name=gpt Filter by model name — partial match |
| providers | Array of strings Example: providers=openai&providers=google Filter by provider — values come from |
| modelTypes | Array of strings Example: modelTypes=chat Filter by model type — values come from |
| useCases | Array of strings Example: useCases=coding Filter by use case — values come from |
| backendTypes | Array of strings Example: backendTypes=selfhost Filter by where the model runs — values come from |
| byGroup | boolean Default: false Example: byGroup=false Group variants of the same model family together |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/models', qs: { page: '1', size: '20', status: 'enabled', name: 'gpt', providers: 'openai,google', modelTypes: 'chat', useCases: 'coding', backendTypes: 'selfhost', byGroup: 'false' } }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "listData": [
- {
- "uuid": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT",
- "code": "gemma-4-31b-it",
- "description": "General-purpose chat model",
- "isFree": false,
- "isEnabled": true,
- "inputPrice": "5671",
- "outputPrice": "14178",
- "unit": "1M tokens",
- "modelStatus": "ACTIVE",
- "types": [
- "chat"
], - "enabledTypes": [
- "chat"
], - "hasGuardrails": false,
- "hasRateLimit": true,
- "provider": {
- "id": 3,
- "name": "Google",
- "code": "google"
}
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}Description, context length, pricing and use cases.
| modelUuid required | string Example: 8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90 Model UUID. Obtain from |
| byGroup | boolean Default: false Example: byGroup=false Return the model grouped with its family |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/models/detail/%7BmodelUuid%7D', qs: {byGroup: 'false'} }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "modelUuid": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "modelName": "Gemma 4 31B IT",
- "modelCode": "gemma-4-31b-it",
- "isEnabled": true,
- "contextLength": "164K",
- "maxInput": "128K",
- "maxOutput": "32K",
- "rpm": "1000",
- "tpm": "2000000",
- "inputPrice": "5671",
- "outputPrice": "14178",
- "status": "ACTIVE",
- "provider": {
- "id": 3,
- "name": "Google",
- "code": "google"
}
}
}const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/models/metadata' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "providers": [
- {
- "id": 3,
- "name": "Google",
- "code": "google"
}
], - "modelTypes": [
- {
- "id": 1,
- "name": "Chat",
- "code": "chat"
}
], - "useCases": [
- {
- "id": 2,
- "name": "Coding",
- "code": "coding"
}
], - "backendTypes": [
- {
- "id": 1,
- "name": "Selfhost",
- "code": "selfhost"
}
]
}
}Turns models on or off for your account. The call is asynchronous.
Before calling: your account must be activated with available credit (GET /v1/user-credit returns status: ACTIVE) and must already have at least one ACTIVE API key.
Each model has a cooldown between state changes — see the 429 response.
| modelUuid required | string Model UUID. Obtain from |
| enabled required | boolean true enables the model for your account |
| types | Array of strings Task types to enable. Only values listed in the model's own |
[- {
- "modelUuid": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "enabled": true,
- "types": [
- "chat"
]
}, - {
- "modelUuid": "c9f0f895-fb49-4e1b-8a73-0d2f6b5e71a4",
- "enabled": false,
- "types": [
- "chat"
]
}
]{- "message": "API key name already exists."
}The platform default limits for this model, broken down by account tier.
| modelUuid required | string Example: 8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90 Model UUID. Obtain from |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/models/rate-limit/%7BmodelUuid%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "modelUuid": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "modelName": "Gemma 4 31B IT",
- "description": "Platform default limits",
- "note": "Applied per account",
- "table": [
- {
- "modelSize": "31B",
- "userType": "normal",
- "requestsPerMinute": 1000,
- "tokensPerMinute": 2000000
}
]
}
}Cost over a time range, grouped by provider and by model. Billable usage only.
| from | integer <int64> Start of range, epoch milliseconds |
| to | integer <int64> End of range, epoch milliseconds |
| apiKeyIds | string Key ids, comma-separated with no spaces. Obtain from |
| providers | string Provider codes, comma-separated. Obtain from |
| modelUuids | string Model UUIDs, comma-separated with no spaces. Obtain from |
{- "from": 1790787600000,
- "to": 1793466000000,
- "providers": "openai,google"
}{- "totalCost": 6438786,
- "byProvider": [
- {
- "provider": "google",
- "cost": 4873409,
- "percentage": 75.7
}, - {
- "provider": "alibaba",
- "cost": 1565377,
- "percentage": 24.3
}
], - "byModel": [
- {
- "modelUuid": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "modelName": "Gemma 4 31B IT",
- "provider": "google",
- "cost": 4873409,
- "percentage": 75.7
}
]
}| year | integer Example: year=2026 Year. Omit for the current year |
| month | integer Example: month=10 Month 1-12. Omit for the current month |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/cost/monthly-trend', qs: {year: '2026', month: '10'} }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "year": 2026,
- "month": 10,
- "days": [
- {
- "date": "2026-10-01",
- "cost": 182340
}, - {
- "date": "2026-10-02",
- "cost": 201110
}
]
}Available balance = (quota - used) + (freeQuota - freeUsed), counting only pools that have not expired. The free pool is consumed first, then quota.
const request = require('request'); const options = {method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/user-credit'}; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "userId": 110769,
- "quota": 5000000,
- "used": 1243500,
- "expiredAt": "2026-12-31T23:59:59.000+07:00",
- "freeQuota": 200000,
- "freeUsed": 200000,
- "expiredFreeAt": "2026-10-31T23:59:59.000+07:00",
- "status": "ACTIVE",
- "uuid": "9c1f4b1c-3a6d-4e90-8f14-e45fceea467a"
}
}| page | integer Example: page=1 Page number, starting at 1. Pagination only applies when BOTH |
| size | integer Example: size=20 Items per page. Must be sent together with |
| name | string Example: name=team- Filter by name — partial match, case-insensitive |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/rate-limit-config', qs: {page: '1', size: '20', name: 'team-'} }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "listData": [
- {
- "id": "a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512",
- "name": "team-a-limit",
- "status": "ACTIVE",
- "requests": true,
- "requestsLimit": 1000,
- "requestsTimeUnit": "minute",
- "requestsWindowType": "fixed",
- "tokens": true,
- "tokensLimit": 2000000,
- "tokensTimeUnit": "minute",
- "tokensWindowType": "fixed",
- "requestsTimeValue": 1,
- "tokensTimeValue": 1,
- "createdAt": "2026-10-05T15:30:00.000+07:00",
- "associatedModels": [
- {
- "models": [
- {
- "id": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT"
}
]
}
], - "associatedApiKeys": [
- {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key"
}
]
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}Creates a rate-limit config and optionally attaches it to models or API keys right away.
| is_requests | boolean Default: false Enable the request-count limit. Note: this field is named |
| requestsLimit | integer <int64> [ 1 .. 100000000 ] Default: 100 Maximum number of requests per window |
| requestsTimeUnit | string Default: "minute" Enum: "minute" "hour" "day" "month" Length of the request-counting window |
| requestsWindowType | string Default: "fixed" Value: "fixed" Always send |
| is_tokens | boolean Default: false Enable the token-count limit. In responses this field is named |
| tokensLimit | integer <int64> [ 100 .. 5000000000 ] Default: 100000 Maximum number of tokens per window |
| tokensTimeUnit | string Default: "minute" Enum: "minute" "hour" "day" "month" Length of the token-counting window |
| tokensWindowType | string Default: "fixed" Value: "fixed" Always send |
| name required | string^[a-z0-9\-]{5,100}$ 5-100 characters: lowercase a-z, digits 0-9 and hyphens only. Uppercase letters, spaces and accented characters are rejected |
| modelUuids | Array of strings Model UUIDs. Obtain from |
| associatedApiKeys | Array of strings Key ids. Obtain from |
{- "name": "team-a-limit",
- "is_requests": true,
- "requestsLimit": 1000,
- "requestsTimeUnit": "minute",
- "requestsWindowType": "fixed",
- "is_tokens": true,
- "tokensLimit": 2000000,
- "tokensTimeUnit": "minute",
- "tokensWindowType": "fixed",
- "modelUuids": [
- "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90"
], - "associatedApiKeys": [
- "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3"
]
}{- "data": {
- "id": "a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512"
}
}| rateLimitConfigId required | string Example: a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512 Rate-limit config id. Obtain from |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/rate-limit-config/%7BrateLimitConfigId%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "id": "a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512",
- "name": "team-a-limit",
- "status": "ACTIVE",
- "requests": true,
- "requestsLimit": 1000,
- "requestsTimeUnit": "minute",
- "requestsWindowType": "fixed",
- "tokens": true,
- "tokensLimit": 2000000,
- "tokensTimeUnit": "minute",
- "tokensWindowType": "fixed",
- "requestsTimeValue": 1,
- "tokensTimeValue": 1,
- "createdAt": "2026-10-05T15:30:00.000+07:00",
- "associatedModels": [
- {
- "models": [
- {
- "id": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT"
}
]
}
], - "associatedApiKeys": [
- {
- "id": "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3",
- "name": "my-service-key"
}
]
}
}| rateLimitConfigId required | string Example: a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512 Rate-limit config id. Obtain from |
| is_requests | boolean Default: false Enable the request-count limit. Note: this field is named |
| requestsLimit | integer <int64> [ 1 .. 100000000 ] Default: 100 Maximum number of requests per window |
| requestsTimeUnit | string Default: "minute" Enum: "minute" "hour" "day" "month" Length of the request-counting window |
| requestsWindowType | string Default: "fixed" Value: "fixed" Always send |
| is_tokens | boolean Default: false Enable the token-count limit. In responses this field is named |
| tokensLimit | integer <int64> [ 100 .. 5000000000 ] Default: 100000 Maximum number of tokens per window |
| tokensTimeUnit | string Default: "minute" Enum: "minute" "hour" "day" "month" Length of the token-counting window |
| tokensWindowType | string Default: "fixed" Value: "fixed" Always send |
| modelUuids | Array of strings Omit to keep the current models. Send a list to REPLACE the whole set — any model not in the list is detached. Send [] to detach all. Obtain from |
{- "is_requests": true,
- "requestsLimit": 2000,
- "requestsTimeUnit": "minute",
- "requestsWindowType": "fixed",
- "is_tokens": false,
- "modelUuids": [
- "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90"
]
}{- "message": "API key name already exists."
}| rateLimitConfigId required | string Example: a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512 Rate-limit config id. Obtain from |
const request = require('request'); const options = { method: 'DELETE', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/rate-limit-config/%7BrateLimitConfigId%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "message": "API key name already exists."
}This endpoint changes the name only. There is no description field.
| rateLimitConfigId required | string Example: a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512 Rate-limit config id. Obtain from |
| name required | string^[a-z0-9\-]{5,100}$ 5-100 characters: lowercase a-z, digits 0-9 and hyphens only. Uppercase letters, spaces and accented characters are rejected |
{- "name": "team-a-limit"
}{- "message": "API key name already exists."
}A model or API key belongs to exactly one rate-limit config. To move one to a different config, detach it from the current config first.
| rateLimitConfigId required | string Example: a7d3e1b8-5c94-4f20-b6e1-93c7a0d4f512 Rate-limit config id. Obtain from |
| modelUuids required | Array of strings REPLACES the whole set of models. Any model currently attached but missing from this list is DETACHED. Send [] to detach all. Obtain from |
| associatedApiKeys | Array of strings Omit this field to keep the currently attached keys. Send [] to detach all. Send a list to replace the whole set. Obtain from |
{- "modelUuids": [
- "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "c9f0f895-fb49-4e1b-8a73-0d2f6b5e71a4"
], - "associatedApiKeys": [
- "auth-5ba35dbd-b2b6-4ec4-94ab-e78bf9613af3"
]
}{- "message": "API key name already exists."
}| page | integer Example: page=1 Page number, starting at 1. Pagination only applies when BOTH |
| size | integer Example: size=20 Items per page. Must be sent together with |
| name | string Example: name=pii- Filter by name — partial match, case-insensitive |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/guardrails', qs: {page: '1', size: '20', name: 'pii-'} }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "listData": [
- {
- "id": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84",
- "name": "pii-block",
- "description": "Block e-mail addresses and national ID numbers",
- "status": "ACTIVE",
- "createdAt": "2026-10-06T09:15:00.000+07:00",
- "pii": {
- "scoreThreshold": 0.6,
- "types": [
- {
- "piiTypeCode": "EMAIL_ADDRESS",
- "action": "replace",
- "replacementValue": "[EMAIL]"
}
]
}, - "wordFilter": {
- "items": [
- {
- "value": "password",
- "category": "sensitive",
- "action": "block"
}
]
}, - "promptBased": [
- {
- "name": "no-legal-advice",
- "description": "Refuse to answer requests for specific legal advice",
- "action": "block"
}
], - "associatedModels": [
- {
- "models": [
- {
- "id": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT"
}
]
}
]
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}Creates a content-control rule set: PII filter, word filter and prompt-based rules.
| name required | string^[a-z0-9\-]{5,100}$ 5-100 characters: lowercase a-z, digits 0-9 and hyphens only. Uppercase letters, spaces and accented characters are rejected |
| description | string <= 255 characters Free-text note so you can recognise this guardrail |
object (PiiConfigCreate) PII settings when CREATING a guardrail — | |
object (WordFilterConfig) | |
Array of objects (PromptRule) |
{- "name": "pii-block",
- "description": "Block e-mail addresses and national ID numbers",
- "pii": {
- "scoreThreshold": 0.6,
- "types": [
- {
- "piiTypeCode": "EMAIL_ADDRESS",
- "action": "replace",
- "replacementValue": "[EMAIL]"
}
]
}, - "wordFilter": {
- "items": [
- {
- "value": "password",
- "category": "sensitive",
- "action": "block"
}
]
}, - "promptBased": [
- {
- "name": "no-legal-advice",
- "description": "Refuse to answer requests for specific legal advice",
- "action": "block"
}
]
}{- "data": {
- "id": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84"
}
}| guardrailsIds required | Array of strings non-empty Guardrail ids to delete. Obtain from |
{- "guardrailsIds": [
- "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84",
- "d4e9a1c7-38b5-4620-9e71-5c8f2a0b6d93"
]
}{- "data": [
- "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84",
- "d4e9a1c7-38b5-4620-9e71-5c8f2a0b6d93"
]
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/guardrails/%7BguardrailsId%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "data": {
- "id": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84",
- "name": "pii-block",
- "description": "Block e-mail addresses and national ID numbers",
- "status": "ACTIVE",
- "createdAt": "2026-10-06T09:15:00.000+07:00",
- "pii": {
- "scoreThreshold": 0.6,
- "types": [
- {
- "piiTypeCode": "EMAIL_ADDRESS",
- "action": "replace",
- "replacementValue": "[EMAIL]"
}
]
}, - "wordFilter": {
- "items": [
- {
- "value": "password",
- "category": "sensitive",
- "action": "block"
}
]
}, - "promptBased": [
- {
- "name": "no-legal-advice",
- "description": "Refuse to answer requests for specific legal advice",
- "action": "block"
}
], - "associatedModels": [
- {
- "models": [
- {
- "id": "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "name": "Gemma 4 31B IT"
}
]
}
]
}
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
const request = require('request'); const options = { method: 'DELETE', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/guardrails/%7BguardrailsId%7D' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "message": "API key name already exists."
}The PII types you can select in a PII filter. Use the code value as piiTypeCode.
const request = require('request'); const options = { method: 'GET', url: 'https://aiplatform-hcm.api.vngcloud.vn/v1/guardrails/pii/types' }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); });
{- "listData": [
- {
- "code": "EMAIL_ADDRESS",
- "groupKey": "CONTACT",
- "displayName": "E-mail address"
}, - {
- "code": "PHONE_NUMBER",
- "groupKey": "CONTACT",
- "displayName": "Phone number"
}
]
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
| name required | string^[a-z0-9\-]{5,100}$ 5-100 characters: lowercase a-z, digits 0-9 and hyphens only. Uppercase letters, spaces and accented characters are rejected |
| description | string <= 255 characters Free-text note so you can recognise this guardrail |
{- "name": "pii-block",
- "description": "Block e-mail addresses and national ID numbers"
}{- "message": "API key name already exists."
}Configures which PII types to detect and any custom regular expressions.
Note the placement of regularExpression: on POST /v1/guardrails it sits inside pii; here it sits alongside pii. Putting it in the wrong place silently drops it.
| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
object (PiiConfig) PII settings when UPDATING — | |
Array of objects (RegexRule) |
{- "pii": {
- "scoreThreshold": 0.6,
- "types": [
- {
- "piiTypeCode": "EMAIL_ADDRESS",
- "action": "replace",
- "replacementValue": "[EMAIL]"
}, - {
- "piiTypeCode": "PHONE_NUMBER",
- "action": "mask",
- "maskChar": "*",
- "maskCount": 4,
- "maskFromEnd": true
}
]
}, - "regularExpression": [
- {
- "name": "national-id",
- "pattern": "\\b\\d{12}\\b",
- "action": "replace",
- "replacementValue": "[ID]"
}
]
}{- "data": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84"
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
Array of objects (PromptRule) |
{- "promptBased": [
- {
- "name": "no-legal-advice",
- "description": "Refuse to answer requests for specific legal advice",
- "action": "block"
}
]
}{- "data": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84"
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
object (WordFilterConfig) |
{- "wordFilter": {
- "items": [
- {
- "value": "password",
- "category": "sensitive",
- "action": "block"
}
]
}
}{- "data": "b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84"
}| guardrailsId required | string Example: b2c8f4a6-71d3-4e95-8f02-6a1b9c3e7d84 Guardrail id. Obtain from |
| modelUuids required | Array of strings REPLACES the whole set of models. Send [] to detach the guardrail from every model. Obtain from |
{- "modelUuids": [
- "8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90",
- "c9f0f895-fb49-4e1b-8a73-0d2f6b5e71a4"
]
}{- "message": "API key name already exists."
}Requests you have sent to models, with filtering and pagination.
| page | integer Page number, starting at 1. Send together with |
| size | integer Items per page. Send together with |
| from | integer <int64> Start of range, epoch milliseconds |
| to | integer <int64> End of range, epoch milliseconds |
| searchFullText | string Full-text search across the log record. Leave empty to skip keyword filtering |
| minCode | integer Lowest HTTP status code to include |
| maxCode | integer Highest HTTP status code to include |
| modelUuids | string Model UUIDs, comma-separated. Obtain from |
| apiKeyIds | string Key ids, comma-separated. Obtain from |
| providers | string Provider codes, comma-separated. Obtain from |
| aggregationType | string Enum: "value_count" "sum" How to aggregate. |
| aggregationField | string Numeric field to sum. Only used when |
| calendarInterval | string Enum: "minute" "hour" "day" "week" "month" "quarter" "year" Time bucket size. Required for |
{- "page": 1,
- "size": 20,
- "from": 1790787600000,
- "to": 1793466000000,
- "minCode": 200,
- "maxCode": 399
}{- "listData": [
- {
- "_index": "gw-2026.10",
- "_type": "_doc",
- "_id": "b3e18f0d9ec20d79d503d70ae6eab212",
- "_score": null,
- "_source": {
- "@timestamp": "2026-10-14T03:55:59.547Z",
- "maas_user_id": "110769",
- "ai": {
- "proxy": {
- "meta": {
- "request_model": "gemma-4-31b-it"
}, - "usage": {
- "prompt_tokens": 18307,
- "completion_tokens": 19,
- "total_tokens": 18326
}
}
}, - "response": {
- "status": 200
}
}
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}| modelUuid required | string Example: 8f14e45f-ceea-467a-9c1f-4b1c3a6d2e90 Model UUID. Obtain from |
| page | integer Page number, starting at 1. Send together with |
| size | integer Items per page. Send together with |
| from | integer <int64> Start of range, epoch milliseconds |
| to | integer <int64> End of range, epoch milliseconds |
| searchFullText | string Full-text search across the log record. Leave empty to skip keyword filtering |
| minCode | integer Lowest HTTP status code to include |
| maxCode | integer Highest HTTP status code to include |
| modelUuids | string Model UUIDs, comma-separated. Obtain from |
| apiKeyIds | string Key ids, comma-separated. Obtain from |
| providers | string Provider codes, comma-separated. Obtain from |
| aggregationType | string Enum: "value_count" "sum" How to aggregate. |
| aggregationField | string Numeric field to sum. Only used when |
| calendarInterval | string Enum: "minute" "hour" "day" "week" "month" "quarter" "year" Time bucket size. Required for |
{- "page": 1,
- "size": 20,
- "from": 1790787600000,
- "to": 1793466000000,
- "minCode": 200,
- "maxCode": 399
}{- "listData": [
- {
- "_index": "gw-2026.10",
- "_type": "_doc",
- "_id": "b3e18f0d9ec20d79d503d70ae6eab212",
- "_score": null,
- "_source": {
- "@timestamp": "2026-10-14T03:55:59.547Z",
- "maas_user_id": "110769",
- "ai": {
- "proxy": {
- "meta": {
- "request_model": "gemma-4-31b-it"
}, - "usage": {
- "prompt_tokens": 18307,
- "completion_tokens": 19,
- "total_tokens": 18326
}
}
}, - "response": {
- "status": 200
}
}
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}Figures aggregated into time buckets, for charting.
| page | integer Page number, starting at 1. Send together with |
| size | integer Items per page. Send together with |
| from | integer <int64> Start of range, epoch milliseconds |
| to | integer <int64> End of range, epoch milliseconds |
| searchFullText | string Full-text search across the log record. Leave empty to skip keyword filtering |
| minCode | integer Lowest HTTP status code to include |
| maxCode | integer Highest HTTP status code to include |
| modelUuids | string Model UUIDs, comma-separated. Obtain from |
| apiKeyIds | string Key ids, comma-separated. Obtain from |
| providers | string Provider codes, comma-separated. Obtain from |
| aggregationType | string Enum: "value_count" "sum" How to aggregate. |
| aggregationField | string Numeric field to sum. Only used when |
| calendarInterval | string Enum: "minute" "hour" "day" "week" "month" "quarter" "year" Time bucket size. Required for |
{- "page": 1,
- "size": 20,
- "from": 1790787600000,
- "to": 1793466000000,
- "minCode": 200,
- "maxCode": 399
}{- "listData": [
- {
- "key_as_string": "2026-10-14T10:00:00.000+07:00",
- "key": 1792000800000,
- "doc_count": 29487
}
], - "page": 1,
- "pageSize": 20,
- "totalPage": 1,
- "totalItem": 1
}