Browse documentationUpload LoRA

POST /api/v1/storage/lora/upload

API version: v1.2.4

Upload custom LoRA model files for video generation with custom styles.

Endpoint

Plain text
POST /api/v1/storage/lora/upload

Authentication

Required. Include your API key in the request header:

Plain text
X-API-Key: your-api-key-here

Request

Content Type

Plain text
multipart/form-data

Form Fields

FieldTypeRequiredDescription
high_noise_filefileYesHigh noise .safetensors file
low_noise_filefileYesLow noise .safetensors file
namestringNoDisplay name for the LoRA model
descriptionstringNoDescription of the LoRA model
tagsstringNoJSON array string of tags (e.g., ["anime", "style"])
default_scalefloatNoDefault LoRA strength (0.0-1.0, default: 1.0)

File Requirements

  • Format: .safetensors only
  • Files: Both high_noise and low_noise files are required
  • Size: Maximum file size depends on server configuration

Response

Success (200 OK)

JSON
{
  "lora_id": "550e8400-e29b-41d4-a716-446655440000",
  "file_id": "lora-550e8400-e29b-41d4-a716-446655440000",
  "name": "My Custom Style",
  "status": "pending",
  "file_size": 524288000,
  "message": "LoRA upload started. Use GET /api/v1/loras/{lora_id}/status to check progress."
}

Response Fields

FieldTypeDescription
lora_idstringUnique UUID identifier for the LoRA model
file_idstringFile identifier (format: lora-{uuid})
namestringDisplay name of the LoRA model
statusstringUpload status: pending, downloading, ready, failed
file_sizeintegerTotal file size in bytes
messagestringInstructions for checking upload progress

Note: Uploaded LoRAs expire after 24 hours. Check expires_at in the status response.

Examples

Upload (cURL)

cURL
curl -X POST https://phosor.ai/api/v1/storage/lora/upload \
  -H "X-API-Key: your-api-key" \
  -F "high_noise_file=@high_noise.safetensors" \
  -F "low_noise_file=@low_noise.safetensors" \
  -F "name=My Custom Style" \
  -F "description=A custom trained LoRA for anime style"

Upload with Tags (Python)

Python
import requests

# Prepare files and metadata
files = {
    "high_noise_file": ("high_noise.safetensors", open("high_noise.safetensors", "rb")),
    "low_noise_file": ("low_noise.safetensors", open("low_noise.safetensors", "rb"))
}

data = {
    "name": "Anime Style LoRA",
    "description": "Custom trained for anime-style character generation",
    "tags": '["anime", "character", "style"]',
    "default_scale": 0.8
}

response = requests.post(
    "https://phosor.ai/api/v1/storage/lora/upload",
    headers={"X-API-Key": "your-api-key"},
    files=files,
    data=data
)

result = response.json()
lora_id = result["lora_id"]
print(f"LoRA upload started: {lora_id}")
print(f"Status: {result['status']}")

Complete Upload Flow

Python
import requests
import time

def upload_lora_and_wait(high_noise_path, low_noise_path, name, api_key):
    """Upload LoRA files and wait for processing to complete"""

    # Step 1: Upload files
    print("Uploading LoRA files...")
    with open(high_noise_path, "rb") as high_f, open(low_noise_path, "rb") as low_f:
        response = requests.post(
            "https://phosor.ai/api/v1/storage/lora/upload",
            headers={"X-API-Key": api_key},
            files={
                "high_noise_file": ("high_noise.safetensors", high_f),
                "low_noise_file": ("low_noise.safetensors", low_f)
            },
            data={"name": name}
        )

    if response.status_code != 200:
        print(f"Upload failed: {response.text}")
        return None

    lora_id = response.json()["lora_id"]
    print(f"Upload started. LoRA ID: {lora_id}")

    # Step 2: Poll for completion
    while True:
        status_response = requests.get(
            f"https://phosor.ai/api/v1/loras/{lora_id}/status",
            headers={"X-API-Key": api_key}
        )
        status_data = status_response.json()
        status = status_data["status"]

        print(f"Status: {status}")

        if status == "ready":
            print("LoRA model is ready to use!")
            return lora_id
        elif status == "failed":
            print(f"Upload failed: {status_data.get('error_message')}")
            return None

        time.sleep(5)

# Usage
lora_id = upload_lora_and_wait(
    "high_noise.safetensors",
    "low_noise.safetensors",
    "My Custom Style",
    "your-api-key"
)

if lora_id:
    print(f"Use this lora_id in /api/v1/inference/submit: {lora_id}")

JavaScript/Node.js Example

JavaScript
const fetch = require('node-fetch');
const FormData = require('form-data');
const fs = require('fs');

async function uploadLora(highNoisePath, lowNoisePath, name, apiKey) {
  const formData = new FormData();
  formData.append('high_noise_file', fs.createReadStream(highNoisePath));
  formData.append('low_noise_file', fs.createReadStream(lowNoisePath));
  formData.append('name', name);

  const response = await fetch('https://phosor.ai/api/v1/storage/lora/upload', {
    method: 'POST',
    headers: {
      'X-API-Key': apiKey
    },
    body: formData
  });

  if (response.ok) {
    const result = await response.json();
    console.log('LoRA upload started:', result.lora_id);
    return result;
  } else {
    console.error('Upload failed:', await response.text());
    return null;
  }
}

// Usage
uploadLora(
  './high_noise.safetensors',
  './low_noise.safetensors',
  'My Custom Style',
  'your-api-key'
).then(result => {
  if (result) {
    console.log('Check status at: /api/v1/loras/' + result.lora_id + '/status');
  }
});

Status Transitions

The upload process is non-blocking. Status transitions are:

Plain text
pending → downloading → ready
                    ↘ failed
  • pending: Upload request received, processing queued
  • downloading: Files being processed and stored in Phosor Storage
  • ready: LoRA model ready for use in video generation
  • failed: Upload failed (check error_message for details)

Error Responses

Invalid File Format (400 Bad Request)

JSON
{
  "error": "Invalid file format",
  "message": "Only .safetensors files are supported"
}

Missing Required Files (400 Bad Request)

JSON
{
  "error": "Missing required files",
  "message": "Both high_noise_file and low_noise_file are required"
}

Unauthorized (401 Unauthorized)

JSON
{
  "error": "API key required",
  "message": "X-API-Key header is required"
}