// Model Management

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.

Base URL
https://api.xerotier.ai/proj_ABC123/v1
Authorization header
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
curl https://api.xerotier.ai/proj_ABC123/v1/models \ -H "Authorization: Bearer xero_myproject_your_api_key"
Python
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']}")
Node.js
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
curl https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000?extended=true \ -H "Authorization: Bearer xero_myproject_your_api_key"
Python
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']}")
Node.js
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
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 }'
Python
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']}")
Node.js
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
curl -X DELETE https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000 \ -H "Authorization: Bearer xero_myproject_your_api_key"
Python
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()}")
Node.js
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
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"
Python
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']}")
Node.js
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" }

Share Model

POST/proj_ABC123/v1/models/{modelId}/share

Shares a model to the public catalog. The catalog role controls how other projects see the model.

Request Body

Parameter Type Description
catalog_roleoptional string One of deployable or shared. deployable (default) lists the model in the catalog so other projects can deploy their own copy. shared additionally lets shared-mode agent endpoints run inference against the source project's deployment. Defaults to deployable when omitted.
curl
curl -X POST https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000/share \ -H "Authorization: Bearer xero_myproject_your_api_key" \ -H "Content-Type: application/json" \ -d '{"catalog_role": "deployable"}'
Python
import requests MODEL_ID = "00000000-1111-0000-1111-000000000000" headers = { "Authorization": "Bearer xero_myproject_your_api_key", "Content-Type": "application/json" } response = requests.post( f"https://api.xerotier.ai/proj_ABC123/v1/models/{MODEL_ID}/share", headers=headers, json={"catalog_role": "deployable"} ) print(response.json())
Node.js
const MODEL_ID = "00000000-1111-0000-1111-000000000000"; const response = await fetch( `https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}/share`, { method: "POST", headers: { "Authorization": "Bearer xero_myproject_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ catalog_role: "deployable" }) } ); console.log(await response.json());

Response

{ "id": "00000000-1111-0000-1111-000000000000", "catalog_role": "deployable", "is_shared": true, "shared_at": "2026-01-15T10:30:00Z" }

Unshare Model

POST/proj_ABC123/v1/models/{modelId}/unshare

Removes a model from the public catalog. After unsharing, the model is no longer discoverable or deployable by other projects. Catalog deployments that other projects already provisioned are not affected.

curl
curl -X POST https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000/unshare \ -H "Authorization: Bearer xero_myproject_your_api_key"
Python
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}/unshare", headers=headers ) print(response.json())
Node.js
const MODEL_ID = "00000000-1111-0000-1111-000000000000"; const response = await fetch( `https://api.xerotier.ai/proj_ABC123/v1/models/${MODEL_ID}/unshare`, { method: "POST", headers: { "Authorization": "Bearer xero_myproject_your_api_key" } } ); console.log(await response.json());

Response

{ "id": "00000000-1111-0000-1111-000000000000", "is_shared": false }

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
curl https://api.xerotier.ai/proj_ABC123/v1/models/00000000-1111-0000-1111-000000000000/catalog-info \ -H "Authorization: Bearer xero_myproject_your_api_key"
Python
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")
Node.js
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 oJump to Overview
g bJump to Base URL
g lJump to List Models
g dJump to Get Model Details
g uJump to Update Model
g xJump to Delete Model
g rJump to Revalidate Model
g sJump to Share Model
g nJump to Unshare Model
g cJump to Catalog Info
g vJump to Model Versions
g eJump to Error Responses
g tJump to Scope Table
?Toggle this shortcuts dialog
EscClose 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/modelsinferenceproject API key
GET/v1/models/{modelId}inferenceproject API key
PATCH/v1/models/{modelId}inferenceproject API key
DELETE/v1/models/{modelId}inferenceproject API key
POST/v1/models/{modelId}/revalidateinferenceproject API key
POST/v1/models/{modelId}/shareinferenceproject API key
POST/v1/models/{modelId}/unshareinferenceproject API key
GET/v1/models/{modelId}/versionsinferenceproject API key
POST/v1/models/{modelId}/versionsinferenceproject API key
POST/v1/models/{modelId}/versions/{version}/promoteinferenceproject API key
POST/v1/models/{modelId}/versions/{version}/rollbackinferenceproject API key
GET/v1/models/{modelId}/catalog-infoinferenceproject API key