Model Upload
Upload complete HuggingFace model directories to Xerotier.ai using archive or directory upload methods.
Overview
Xerotier.ai supports two methods for uploading complete model directories:
| Method | Best For | Key Features |
|---|---|---|
| Archive Upload | Standard model uploads | Create a .tar.gz archive, upload in chunks, server extracts |
| Directory Upload | Large models, incremental uploads | Upload files individually, fine-grained control |
Both methods use chunked uploads for reliability and support the same model formats. For basic chunked file uploads, see the Model Management API reference.
Archive Upload
Upload compressed archives containing HuggingFace model directories. Archives are extracted server-side, preserving the model's file structure for vLLM compatibility.
Best for: Uploading complete HuggingFace model directories. Supports .tar, .tar.gz, and .tar.bz2 formats.
Supported Formats
| Format | Extension | Content-Type |
|---|---|---|
| tar | .tar |
application/x-tar |
| tar.gz | .tar.gz, .tgz |
application/gzip |
| tar.bz2 | .tar.bz2, .tbz2 |
application/x-bzip2 |
Creating an Archive
Create a properly formatted archive from your model directory. Files must be at the archive root (not nested in subdirectories).
COPYFILE_DISABLE=1 tar -chzf model-name.tar.gz -C /path/to/model/directory .
Command Options
| Option | Description |
|---|---|
-c |
Create a new archive |
-h |
Follow symlinks (required for HuggingFace cache) |
-z |
Compress with gzip (use -j for bzip2) |
-f |
Specify the output filename |
-C |
Change to directory before adding files |
Important: The -h flag is required when archiving from HuggingFace cache, as it uses symlinks. Without this flag, your archive will contain broken links instead of actual model files.
HuggingFace Cache Example
# Find and archive a model from HuggingFace cache
COPYFILE_DISABLE=1 tar -chzf Qwen3-0.6B.tar.gz -C ~/.cache/huggingface/hub/models--Qwen--Qwen3-0.6B/snapshots/abc123/ .
Verify Archive Structure
Before uploading, verify files are at the root level:
$ tar -tzf model-name.tar.gz | head -5
./config.json
./model.safetensors
./tokenizer.json
./tokenizer_config.json
./generation_config.json
Initialize Archive Upload
POST /proj_ABC123/v1/uploads/archive
Request Body
| Parameter | Type | Description |
|---|---|---|
| model_namerequired | string | Display name for the model |
| archive_sizerequired | integer | Total archive size in bytes |
| archive_formatrequired | string | Archive format: "tar", "tar.gz", or "tar.bz2" |
curl -X POST https://api.xerotier.ai/proj_ABC123/v1/uploads/archive \
-H "Authorization: Bearer xero_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model_name": "Qwen3-0.6B",
"archive_size": 1234567890,
"archive_format": "tar.gz"
}'
Response
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"upload_url": "https://api.xerotier.ai/proj_ABC123/v1/uploads/550e8400.../chunks",
"chunk_size": 104857600,
"total_chunks": 12,
"expires_at": "2026-01-02T00:00:00Z"
}
Upload Archive Chunks
After initialization, upload chunks using the same chunked upload process as single-file uploads:
POST /proj_ABC123/v1/uploads/{sessionId}/parts?part_number={chunkIndex}
Complete Archive Upload
When all chunks are uploaded, complete the upload to trigger archive extraction:
POST /proj_ABC123/v1/uploads/{sessionId}/complete
Response
{
"model_id": "660e8400-e29b-41d4-a716-446655440001",
"model_name": "Qwen3-0.6B",
"file_count": 7,
"total_size": 1234567890,
"files": [
{"relative_path": "config.json", "size": 1234, "content_type": "application/json"},
{"relative_path": "model.safetensors", "size": 1234000000, "content_type": "application/octet-stream"},
{"relative_path": "tokenizer.json", "size": 5678, "content_type": "application/json"}
],
"status": "completed"
}
Archive Upload Example
import os
import hashlib
import requests
API_KEY = "xero_myproject_your_api_key"
BASE_URL = "https://api.xerotier.ai/proj_ABC123/v1"
def upload_archive(archive_path: str, model_name: str):
archive_size = os.path.getsize(archive_path)
# Initialize
init = requests.post(f"{BASE_URL}/uploads/archive",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"model_name": model_name, "archive_size": archive_size, "archive_format": "tar.gz"}
).json()
session_id = init["session_id"]
chunk_size = init["chunk_size"]
# Upload chunks
with open(archive_path, "rb") as f:
idx = 0
while chunk := f.read(chunk_size):
checksum = hashlib.sha256(chunk).hexdigest()
requests.post(f"{BASE_URL}/uploads/{session_id}/parts?part_number={idx}",
headers={"Authorization": f"Bearer {API_KEY}", "X-Chunk-Checksum": checksum},
data=chunk)
idx += 1
# Complete
return requests.post(f"{BASE_URL}/uploads/{session_id}/complete",
headers={"Authorization": f"Bearer {API_KEY}"}).json()
upload_archive("./qwen3-0.6b.tar.gz", "Qwen3-0.6B")
Directory Upload
Upload individual files that mirror a local model directory structure. Useful when creating an archive is impractical or for incremental uploads.
Best for: Large models where archive creation is slow, or when you want fine-grained control over individual file uploads.
Initialize Directory Upload
POST /proj_ABC123/v1/uploads/directory
Provide a manifest of all files to upload:
Request Body
| Parameter | Type | Description |
|---|---|---|
| model_namerequired | string | Display name for the model |
| filesrequired | array | List of files with relative_path and size |
curl -X POST https://api.xerotier.ai/proj_ABC123/v1/uploads/directory \
-H "Authorization: Bearer xero_myproject_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model_name": "Qwen3-0.6B",
"files": [
{"relative_path": "config.json", "size": 1234},
{"relative_path": "model.safetensors", "size": 1234000000},
{"relative_path": "tokenizer.json", "size": 5678}
]
}'
Response
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"upload_url": "https://api.xerotier.ai/proj_ABC123/v1/uploads/550e8400.../files",
"files": [
{"relative_path": "config.json", "upload_path": ".../files/config.json", "size": 1234},
{"relative_path": "model.safetensors", "upload_path": ".../files/model.safetensors", "size": 1234000000}
],
"expires_at": "2026-01-02T00:00:00Z"
}
Upload Individual File
POST /proj_ABC123/v1/uploads/{sessionId}/files/{relativePath}
Headers
| Header | Description |
|---|---|
| X-File-Checksum | SHA256 checksum of the file content (hex-encoded) |
CHECKSUM=$(sha256sum config.json | cut -d' ' -f1)
curl -X POST "https://api.xerotier.ai/proj_ABC123/v1/uploads/$SESSION_ID/files/config.json" \
-H "Authorization: Bearer xero_myproject_your_api_key" \
-H "X-File-Checksum: $CHECKSUM" \
--data-binary @config.json
Response
{
"relative_path": "config.json",
"size": 1234,
"checksum": "a1b2c3d4e5f6...",
"uploaded_file_count": 1,
"expected_file_count": 7,
"progress": 14.28
}
Directory Upload Example
import os
import hashlib
import requests
from pathlib import Path
API_KEY = "xero_myproject_your_api_key"
BASE_URL = "https://api.xerotier.ai/proj_ABC123/v1"
def upload_directory(model_dir: str, model_name: str):
model_path = Path(model_dir)
# Build manifest
files = [{"relative_path": str(f.relative_to(model_path)), "size": f.stat().st_size}
for f in model_path.rglob("*") if f.is_file()]
# Initialize
init = requests.post(f"{BASE_URL}/uploads/directory",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"model_name": model_name, "files": files}
).json()
session_id = init["session_id"]
# Upload each file
for file_info in files:
file_path = model_path / file_info["relative_path"]
with open(file_path, "rb") as f:
data = f.read()
checksum = hashlib.sha256(data).hexdigest()
requests.post(f"{BASE_URL}/uploads/{session_id}/files/{file_info['relative_path']}",
headers={"Authorization": f"Bearer {API_KEY}", "X-File-Checksum": checksum},
data=data)
# Complete
return requests.post(f"{BASE_URL}/uploads/{session_id}/complete",
headers={"Authorization": f"Bearer {API_KEY}"}).json()
upload_directory("./models--Qwen--Qwen3-0.6B", "Qwen3-0.6B")
Required Model Files
For vLLM compatibility, models must include:
| File | Required | Description |
|---|---|---|
config.json |
Yes | Model configuration |
*.safetensors or *.bin or *.exl2 |
Yes | Model weights (at least one) |
tokenizer.json |
No | Tokenizer configuration |
tokenizer_config.json |
No | Tokenizer settings |