| Purpose | URL |
|---|---|
| AI model calls & OpenAI-compatible API | https://platform.dataeyes.ai |
| Platform management API (this document) | https://www.dataeyes.ai/apex |
Important: All endpoints in this document use https://www.dataeyes.ai/apexas the base URL (thewwwprefix is required).platform.dataeyes.aiserves only/v1/model endpoints and does not provide management APIs.
Authorization: Bearer <system_access_token>
apex-api-user: <user_numeric_id>| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <system_access_token>. Generate and copy it in the console under "Personal Settings → Account Management → Security Settings" |
apex-api-user | Yes | Your account's numeric ID. Contact the platform administrator to obtain it |
The system access token and the numeric user ID must belong to the same account; a mismatch returns 401. The system access token carries key-management privileges. Treat it with the highest sensitivity level and reset it immediately in the console if leaked. All endpoints operate only on keys owned by the authenticated account.
remain_quota) uses the platform's internal quota unit:500,000 quota units = 1 US dollar ($1)| remain_quota | USD |
|---|---|
| 50000 | $0.1 |
| 500000 | $1 |
| 5000000 | $10 |
| 50000000 | $100 |
remain_quota.unlimited_quota is true, the key is not subject to quota limits and remain_quota is ignored.group field determines which channel resource pool the key routes to, and maps to a different billing multiplier. This is the most common pitfall when provisioning keys — please read it carefully.group is an empty string, the key uses the account's default group. On some accounts the default group has no channel bound, in which case calling a model with such a key returns:{"error":{"code":"model_not_found","message":"分组 xxx 下模型 yyy 无可用渠道(distributor)","type":"server_error"}}GET /api/user/self/groupsratio (lower is cheaper):{
"data": {
"claude": {
"cl-cc-pro": {"desc": "...", "desc_en": "...", "ratio": 0.17},
"cl-of-pro": {"desc": "...", "desc_en": "...", "ratio": 0.8}
},
"gemini": { "gm-of-pro": {"desc": "...", "ratio": 0.68} }
},
"message": "",
"success": true
}cl-cc-pro) into the key's group field.PUT /api/token/, or right after creating a key, the gateway holds a token cache, so the group change takes a few seconds (up to ~15s observed) to take effect on the model-call side. During this window:| Symptom | Cause | Action |
|---|---|---|
group X has no available channel for model Y | Group X has no channel bound for model Y | Switch to a group that carries the model; confirm with GET /api/user/self/groups |
| Still reports the old group has no channel right after a group change | Token cache not yet refreshed | Wait ~15s and retry |
| A discounted group intermittently has no channel | Limited concurrency/stability of the discounted pool | Use a stable group, or retry later |
curl --data @file (file saved as UTF-8) or an HTTP client library in your programming language instead;POST /api/token/| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Key name, up to 50 characters |
remain_quota | Integer | Yes | Initial quota (internal quota units), ≥ 0 |
unlimited_quota | Boolean | Yes | Unlimited quota flag; when true, remain_quota is ignored |
expired_time | Integer | Yes | Expiration time (Unix timestamp in seconds); -1 means never expires |
group | String | No | Group; empty string uses the account's default group. The default group may have no available channel — specify a valid group explicitly; see "Groups" |
model_limits_enabled | Boolean | No | Whether the model allowlist is enabled |
model_limits | String | No | Model allowlist, comma-separated |
allow_ips | String | No | IP allowlist; empty means unrestricted |
{"message": "", "success": true}The create endpoint does not return the key material directly. Call "List Keys" or "Search Keys" afterwards to obtain the new key's idandkey.
GET /api/token/?p=1&size=20| Parameter | Description |
|---|---|
p | Page number, starting from 1 |
size | Items per page |
{
"data": {
"page": 1,
"page_size": 20,
"total": 3,
"items": [
{
"id": 31333,
"user_id": 669,
"key": "PqXk****************************",
"status": 1,
"name": "prod-key-01",
"created_time": 1784712786,
"accessed_time": 1784712786,
"expired_time": -1,
"remain_quota": 5000000,
"unlimited_quota": false,
"used_quota": 0,
"group": ""
}
]
},
"message": "",
"success": true
}| Field | Type | Description |
|---|---|---|
id | Integer | Key ID; used for update/delete operations |
key | String | Key material (prepend sk- when calling model APIs) |
status | Integer | Status: 1 enabled, 2 disabled, 3 expired, 4 exhausted |
remain_quota | Integer | Remaining quota (internal quota units) |
used_quota | Integer | Cumulative consumed quota |
unlimited_quota | Boolean | Unlimited quota flag |
expired_time | Integer | Expiration timestamp; -1 means never expires |
GET /api/token/{id}
GET /api/token/search?keyword=<name_keyword>PUT /api/token/⚠️ Important: This is a full-overwrite update
The request body must include all writable fields of the key — the record is overwritten as a whole. If you send only idandremain_quota, the key name will be cleared and the expiration time will be set to 0 (immediately expired).Standard procedure: GET /api/token/{id}to fetch all current fields → modify only the target fields → write the whole object back.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer | Yes | Key ID |
name | String | Yes | Key name (fill in current value) |
remain_quota | Integer | Yes | Target remaining quota (absolute value, not a delta) |
unlimited_quota | Boolean | Yes | Unlimited quota flag |
expired_time | Integer | Yes | Expiration timestamp (fill in current value) |
status | Integer | Yes | Status (fill in current value) |
group | String | Yes | Group (fill in current value) |
model_limits_enabled | Boolean | Yes | Fill in current value |
model_limits | String | Yes | Fill in current value |
allow_ips | String | Yes | Fill in current value |
{
"data": { "id": 31333, "remain_quota": 250000, "...": "..." },
"message": "",
"success": true
}unlimited_quota is false, remain_quota must be non-negative and must not exceed the system maximumremain_quota is a target value: to top up a key, compute current value + increment yourself and send the resultexpired_time / remain_quota firststatus_only parameter — no need to fill in all fields:status: 1 enabled, 2 disabled.DELETE /api/token/{id}{"message": "", "success": true}Deletion takes effect immediately and cannot be undone. Proceed with caution.
| Scenario | Response | Suggested Action |
|---|---|---|
| Token missing/invalid/mismatched with user ID | {"code":401,"msg":"..."} | Verify the system access token and apex-api-user belong to the same account |
| Key not found or not owned by this account | {"success":false,"message":"record not found"} | Check the key id |
| Negative quota / exceeds maximum | {"success":false,"message":"..."} | Fix remain_quota |
| Name too long | {"success":false,"message":"..."} | Name must be ≤ 50 characters |
apex-api-user.remain_quota is a target value; both increases and decreases take effect immediately.GET /api/user/self/groups and switch to a valid group. See "Groups".| Version | Date | Notes |
|---|---|---|
| v1.0 | 2026-07-22 | Initial release: create, query, quota adjustment, enable/disable, delete — full lifecycle verified in production |