Model Management
List, update, share, revalidate, and delete every custom model in your project from one REST surface. Mounted on the inference route group, gated by the same project API key you already use for chat completions.
Note: Model Management API endpoints use the path /proj_ABC123/v1/models. Mutations (PATCH, DELETE, POST share/unshare/revalidate/versions) run on the same inference route group as /v1/chat/completions, gated by standard project API-key authentication. There is no separate "Model Management" scope; any valid project API key is accepted. See the Endpoint scope table below.
The Model Management API allows you to:
- List all models in your project
- Retrieve details for a specific model
- Update model metadata (description, architecture, quantization, and more)
- Delete models you no longer need
- Trigger model revalidation to re-extract metadata
- Share a model to the public catalog or unshare it
- List, create, promote, and roll back model versions
- View catalog information for shared models
For uploading models, see the Model Upload guide. For versioning details, see Model Versioning.
Base URL
Every endpoint below is mounted under one project-scoped base URL. Substitute your project external id and your API key once; the remaining sections show only the path and the body.
https://api.xerotier.ai/proj_ABC123/v1
Authorization: Bearer xero_myproject_your_api_key
The external id has the shape ws_<hex> for workspaces and is visible in the project header. The API key format is xero_<project>_<secret> and is issued from the API Keys page.
List Project Models
GET/proj_ABC123/v1/models
Lists all models uploaded to your project. The default response is the OpenAI-compatible list envelope. Pass ?extended=true to receive Xerotier-specific metadata fields (format, size, status, architecture, version, sharing, and more) along with pagination counters.
curl https://api.xerotier.ai/proj_ABC123/v1/models \
-H "Authorization: Bearer xero_myproject_your_api_key"
import requests
headers = {"Authorization": "Bearer xero_myproject_your_api_key"}
response = requests.get(
"https://api.xerotier.ai/proj_ABC123/v1/models",
headers=headers
)
for model in response.json()["data"]:
print(f"{model['id']} ({model.get('name', '')}) owned_by={model['owned_by']}")
const response = await fetch(
"https://api.xerotier.ai/proj_ABC123/v1/models",
{
headers: {
"Authorization": "Bearer xero_myproject_your_api_key"
}
}
);
const payload = await response.json();
for (const model of payload.data) {
console.log(`${model.id} (${model.name ?? ""}) owned_by=${model.owned_by}`);
}
Response (standard)
{
"object": "list",
"data": [
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"created": 1706123456,
"owned_by": "my-project",
"name": "my-custom-model"
}
]
}
Response (extended)
Request with ?extended=true. Optional fields are omitted from the JSON body when unset (the encoder does not emit explicit null).
{
"object": "list",
"data": [
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"created": 1706123456,
"owned_by": "my-project",
"name": "my-custom-model",
"format": "safetensors",
"size_bytes": 4294967296,
"size_formatted": "4.00 GB",
"status": "ready",
"version": "1.0.0",
"is_latest": true,
"architecture": "LlamaForCausalLM",
"quantization": "awq",
"context_length": 32768,
"parameter_count": 7000000000,
"workload_type": "chat",
"is_shared": false
}
],
"has_more": false,
"total": 1
}
Get Model Details
GET/proj_ABC123/v1/models/{modelId}
Retrieves detailed information about a specific model. Pass ?extended=true to include additional metadata such as format, size, architecture, and catalog status.
curl https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000?extended=true \
-H "Authorization: Bearer xero_myproject_your_api_key"
import requests
MODEL_ID = "00000000-1111-0000-1111-000000000000"
headers = {"Authorization": "Bearer xero_myproject_your_api_key"}
response = requests.get(
f"https://api.xerotier.ai/proj_ABC123/v1/models/{MODEL_ID}",
params={"extended": "true"},
headers=headers
)
model = response.json()
print(f"{model['name']} - {model['status']}")
const MODEL_ID = "00000000-1111-0000-1111-000000000000";
const response = await fetch(
`https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}?extended=true`,
{
headers: {
"Authorization": "Bearer xero_myproject_your_api_key"
}
}
);
const model = await response.json();
console.log(`${model.name} - ${model.status}`);
Response (standard)
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"created": 1706123456,
"owned_by": "my-project",
"name": "my-custom-model"
}
Response (extended)
Optional fields are omitted from the JSON body when unset; do not rely on a key being present with an explicit null value.
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"created": 1706123456,
"owned_by": "my-project",
"name": "my-custom-model",
"format": "safetensors",
"size_bytes": 4294967296,
"size_formatted": "4.00 GB",
"status": "ready",
"version": "1.0.0",
"is_latest": true,
"description": "A fine-tuned LLM for code generation",
"architecture": "LlamaForCausalLM",
"quantization": "awq",
"context_length": 32768,
"parameter_count": 7000000000,
"workload_type": "chat",
"is_shared": false
}
Update Model Metadata
PATCH/proj_ABC123/v1/models/{modelId}
Updates metadata fields on an existing model. All fields in the request body are optional, only provided fields will be updated.
Request Body
| Parameter | Type | Description |
|---|---|---|
| descriptionoptional | string | Description of the model |
| licenseoptional | string | License identifier (e.g., "Apache-2.0") |
| architectureoptional | string | Model architecture (e.g., "LlamaForCausalLM") |
| quantizationoptional | string | Quantization method. Must be one of the runtime-supported values: native, awq, bitsandbytes, bitblas, gguf, gptq, ipex, int4, int8, fp8, modelopt, quark, torchao, or compressed-tensors. Any other non-empty value returns HTTP 400 with "Invalid quantization method: <value>". Passing the empty string skips validation and is treated as "do not change". |
| context_lengthoptional | integer | Maximum context length in tokens |
| parameter_countoptional | integer | Total number of model parameters |
| hidden_sizeoptional | integer | Hidden dimension size extracted from model config |
| num_layersoptional | integer | Number of transformer layers |
| vocab_sizeoptional | integer | Vocabulary size extracted from model config |
| workload_typeoptional | string | Workload type: chat, code, reasoning, embedding, or multilingual. Defaults to chat. |
curl -X PATCH https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000 \
-H "Authorization: Bearer xero_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"description": "Fine-tuned for code generation tasks",
"architecture": "LlamaForCausalLM",
"context_length": 32768
}'
import requests
MODEL_ID = "00000000-1111-0000-1111-000000000000"
headers = {
"Authorization": "Bearer xero_myproject_your_api_key",
"Content-Type": "application/json"
}
response = requests.patch(
f"https://api.xerotier.ai/proj_ABC123/v1/models/{MODEL_ID}",
headers=headers,
json={
"description": "Fine-tuned for code generation tasks",
"architecture": "LlamaForCausalLM",
"context_length": 32768
}
)
model = response.json()
print(f"Updated: {model['name']}")
const MODEL_ID = "00000000-1111-0000-1111-000000000000";
const response = await fetch(
`https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}`,
{
method: "PATCH",
headers: {
"Authorization": "Bearer xero_myproject_your_api_key",
"Content-Type": "application/json"
},
body: JSON.stringify({
description: "Fine-tuned for code generation tasks",
architecture: "LlamaForCausalLM",
context_length: 32768
})
}
);
const model = await response.json();
console.log(`Updated: ${model.name}`);
Response
Optional fields that have no value are omitted entirely rather than emitted as null. For example, if parameter_count has not been set, the key will be absent from the body.
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"created": 1706123456,
"owned_by": "my-project",
"name": "my-custom-model",
"format": "safetensors",
"size_bytes": 4294967296,
"size_formatted": "4.00 GB",
"status": "ready",
"version": "1.0.0",
"is_latest": true,
"description": "Fine-tuned for code generation tasks",
"architecture": "LlamaForCausalLM",
"quantization": "native",
"context_length": 32768,
"workload_type": "chat",
"is_shared": false
}
Delete Model
DELETE/proj_ABC123/v1/models/{modelId}
Permanently deletes a model from your project. This action cannot be undone.
Cascade Deletion: Deleting a model removes associated rows in the project owned by the model. The exact set of dependent records (for example endpoints, endpoint workers, routing rules, model-shared entries, version rows, and any pending tasks) is owned by the model service and database constraints; treat this list as informational. This action cannot be undone.
Requirements
- Valid project API key (the standard inference API-key authentication)
- The model must belong to the calling project
curl -X DELETE https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000 \
-H "Authorization: Bearer xero_myproject_your_api_key"
import requests
API_KEY = "xero_myproject_your_api_key"
BASE_URL = "https://api.xerotier.ai/proj_ABC123/v1"
MODEL_ID = "00000000-1111-0000-1111-000000000000"
response = requests.delete(
f"{BASE_URL}/models/{MODEL_ID}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
if response.status_code == 200:
print(f"Model {MODEL_ID} deleted successfully")
else:
print(f"Error: {response.json()}")
const MODEL_ID = "00000000-1111-0000-1111-000000000000";
const response = await fetch(
`https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}`,
{
method: "DELETE",
headers: {
"Authorization": "Bearer xero_myproject_your_api_key"
}
}
);
if (response.ok) {
console.log(`Model ${MODEL_ID} deleted successfully`);
} else {
const error = await response.json();
console.log(`Error: ${JSON.stringify(error)}`);
}
Response
{
"id": "00000000-1111-0000-1111-000000000000",
"object": "model",
"deleted": true
}
Revalidate Model
POST/proj_ABC123/v1/models/{modelId}/revalidate
Triggers re-validation of a model. The endpoint queues a revalidation job via the database service and returns status: "validating" immediately on success; the model row's status column is updated by the worker that picks up the job. Whether the request is accepted depends on the model's current status as enforced by the database service. Errors are surfaced as 404 Model not found.
curl -X POST https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000/revalidate \
-H "Authorization: Bearer xero_myproject_your_api_key"
import requests
MODEL_ID = "00000000-1111-0000-1111-000000000000"
headers = {"Authorization": "Bearer xero_myproject_your_api_key"}
response = requests.post(
f"https://api.xerotier.ai/proj_ABC123/v1/models/{MODEL_ID}/revalidate",
headers=headers
)
result = response.json()
print(f"Status: {result['status']} - {result['message']}")
const MODEL_ID = "00000000-1111-0000-1111-000000000000";
const response = await fetch(
`https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}/revalidate`,
{
method: "POST",
headers: {
"Authorization": "Bearer xero_myproject_your_api_key"
}
}
);
const result = await response.json();
console.log(`Status: ${result.status} - ${result.message}`);
Response
{
"id": "00000000-1111-0000-1111-000000000000",
"status": "validating",
"message": "Model validation queued"
}
Get Catalog Info
GET/proj_ABC123/v1/models/{modelId}/catalog-info
Returns catalog information for a model that has been shared to the public catalog. Returns 404 if the model is not in the catalog.
Response Fields
| Field | Type | Description |
|---|---|---|
| id | string | Model id. |
| catalog_role | string | One of deployable or shared. See the Share Model section for the meaning of each. |
| deployment_count | integer | Number of projects that have deployed this model from the catalog. |
| is_on_shared_agents | boolean | Derived. true when catalog_role == "shared"; false otherwise. |
| is_public | boolean | Whether the catalog entry is discoverable by other projects. |
| featured | boolean | Editorial flag set by platform operators; not user-controlled. |
| shared_at | string | ISO-8601 timestamp of the first share. |
curl https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000/catalog-info \
-H "Authorization: Bearer xero_myproject_your_api_key"
import requests
MODEL_ID = "00000000-1111-0000-1111-000000000000"
headers = {"Authorization": "Bearer xero_myproject_your_api_key"}
response = requests.get(
f"https://api.xerotier.ai/proj_ABC123/v1/models/{MODEL_ID}/catalog-info",
headers=headers
)
if response.status_code == 200:
info = response.json()
print(f"Role: {info['catalog_role']}, Deployments: {info['deployment_count']}")
else:
print("Model is not in the catalog")
const MODEL_ID = "00000000-1111-0000-1111-000000000000";
const response = await fetch(
`https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}/catalog-info`,
{
headers: {
"Authorization": "Bearer xero_myproject_your_api_key"
}
}
);
if (response.ok) {
const info = await response.json();
console.log(`Role: ${info.catalog_role}, Deployments: ${info.deployment_count}`);
} else {
console.log("Model is not in the catalog");
}
Response
{
"id": "00000000-1111-0000-1111-000000000000",
"catalog_role": "deployable",
"deployment_count": 5,
"is_on_shared_agents": false,
"is_public": true,
"featured": false,
"shared_at": "2026-01-15T10:30:00Z"
}
Model Versions
Four endpoints manage model versions. Detailed semantics and request bodies are covered in the Model Versioning guide; the endpoint surface is summarized here.
| Method | Path | Purpose |
|---|---|---|
| GET | /proj_ABC123/v1/models/{modelId}/versions |
List all versions of a model. |
| POST | /proj_ABC123/v1/models/{modelId}/versions |
Create a new version row for a model. |
| POST | /proj_ABC123/v1/models/{modelId}/versions/{version}/promote |
Promote the named version to be the latest. |
| POST | /proj_ABC123/v1/models/{modelId}/versions/{version}/rollback |
Roll back to the named version. |
Error Responses
Every endpoint in this surface returns OpenAI-shaped error envelopes. The four error classes below cover the failure modes you are likely to hit when integrating.
401 Unauthorized
Returned when no Authorization header is present or the bearer token is malformed.
{
"error": {
"message": "Missing or invalid Authorization header",
"type": "invalid_request_error",
"code": "missing_authorization"
}
}
403 Forbidden
Returned when the API key is valid but belongs to a different project than the one in the URL path, or when the key has been revoked.
{
"error": {
"message": "API key does not authorize access to this project",
"type": "invalid_request_error",
"code": "project_mismatch"
}
}
404 Model not found
Returned by every /models/{modelId} endpoint when the model id does not exist in the calling project. Also returned by catalog-info when the model exists but is not in the public catalog.
{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found"
}
}
400 Invalid quantization method
Returned by PATCH /models/{modelId} when the quantization body field is a non-empty value that is not in the runtime-supported set. The offending value is echoed in the message for diagnosis.
{
"error": {
"message": "Invalid quantization method: fp4",
"type": "invalid_request_error",
"code": "invalid_quantization"
}
}
Keyboard Shortcuts
This page registers a small set of chord shortcuts for jumping between endpoints. Shortcuts are suppressed while typing in inputs, textareas, or contenteditable surfaces. Press ? to toggle the help dialog.
| Chord | Action |
|---|---|
| g o | Jump to Overview |
| g b | Jump to Base URL |
| g l | Jump to List Models |
| g d | Jump to Get Model Details |
| g u | Jump to Update Model |
| g x | Jump to Delete Model |
| g r | Jump to Revalidate Model |
| g s | Jump to Share Model |
| g n | Jump to Unshare Model |
| g c | Jump to Catalog Info |
| g v | Jump to Model Versions |
| g e | Jump to Error Responses |
| g t | Jump to Scope Table |
| ? | Toggle this shortcuts dialog |
| Esc | Close the shortcuts dialog |
Endpoint Scope Table
All Model Management endpoints below are mounted on the project inference route group and gated by the same project API-key middleware as /v1/chat/completions. There is no separate models or Model Management scope enforced at the route layer at this time; any valid project API key is accepted. A scope gate of this kind is tracked as a cross-cutting follow-up and may change in a future release.
| Method | Path | Route group | Auth |
|---|---|---|---|
| GET | /v1/models | inference | project API key |
| GET | /v1/models/{modelId} | inference | project API key |
| PATCH | /v1/models/{modelId} | inference | project API key |
| DELETE | /v1/models/{modelId} | inference | project API key |
| POST | /v1/models/{modelId}/revalidate | inference | project API key |
| POST | /v1/models/{modelId}/share | inference | project API key |
| POST | /v1/models/{modelId}/unshare | inference | project API key |
| GET | /v1/models/{modelId}/versions | inference | project API key |
| POST | /v1/models/{modelId}/versions | inference | project API key |
| POST | /v1/models/{modelId}/versions/{version}/promote | inference | project API key |
| POST | /v1/models/{modelId}/versions/{version}/rollback | inference | project API key |
| GET | /v1/models/{modelId}/catalog-info | inference | project API key |