Skip to main content
This guide demonstrates how to upload files to an Oxen repository using the HTTP API. We’ll break down the process into simple, manageable steps.

Overview

Uploading a file to Oxen involves three main steps:
  1. Create a repository (if it doesn’t exist)
  2. Upload the file to a specific branch
  3. Optionally create additional branches from the uploaded content

Prerequisites

Before you begin, you’ll need:
  • API Key: Authentication token for your Oxen account
  • Server URL: The Oxen server endpoint (e.g., https://hub.oxen.ai or your local server)
  • File to upload: The local file you want to add to your repository

Configuration

First, set up your configuration variables:
# Server Configuration
SERVER_URL = "https://hub.oxen.ai"
API_KEY = "your-api-key-here"

# Repository Configuration
NAMESPACE = "your-username"
REPO_NAME = "my-dataset"
DESCRIPTION = "Example dataset created via HTTP API"

# User Configuration (for commits)
USER_NAME = "Your Name"
USER_EMAIL = "[email protected]"

# Branch Configuration
SOURCE_BRANCH = "main"

# File Upload Configuration
LOCAL_FILE_PATH = "./example.txt"
REMOTE_FILE_PATH = "data/example.txt"
COMMIT_MESSAGE = "Add file via HTTP API"

Step 1: Create a Repository

Create a new repository to store your files. If the repository already exists, this step will return a 409 status code and you can continue.

Endpoint

POST /api/repos

Example

import requests

def create_repository(base_url, api_key, namespace, name, user_name, user_email, description):
    url = f"{base_url}/api/repos"
    
    headers = {
        'Authorization': f'Bearer {api_key}'
    }
    
    payload = {
        "namespace": namespace,
        "name": name,
        "user": {
            "name": user_name,
            "email": user_email
        },
        "description": description
    }
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        print("✓ Repository created successfully")
        return response.json()
    elif response.status_code == 409:
        print("⚠ Repository already exists")
        return response.json()
    else:
        print(f"✗ Failed: {response.status_code}")
        print(response.text)
        return None

# Usage
create_repository(
    base_url="https://hub.oxen.ai",
    api_key="your-api-key",
    namespace="your-username",
    name="my-dataset",
    user_name="Your Name",
    user_email="[email protected]",
    description="Example dataset"
)

Request Body

FieldTypeRequiredDescription
namespacestringYesYour username or organization name
namestringYesRepository name
user.namestringYesAuthor name for commits
user.emailstringYesAuthor email for commits
descriptionstringNoRepository description

Response

{
  "namespace": "your-username",
  "name": "my-dataset",
  "description": "Example dataset created via HTTP API",
  "created_at": "2026-01-08T21:28:00Z"
}

Step 2: Upload a File

Upload a file to your repository. This creates a commit on the specified branch with your file.

Endpoint

PUT /api/repos/{namespace}/{repo_name}/file/{branch}/{path}

Path Parameters

ParameterDescriptionExample
namespaceYour username or organizationyour-username
repo_nameRepository namemy-dataset
branchTarget branch namemain
pathDestination path in repositorydata/example.txt

Example

import os
import requests

def upload_file(base_url, api_key, namespace, repo_name, branch, 
                local_file_path, remote_file_path, commit_message, 
                author_name, author_email):
    # Check if file exists
    if not os.path.exists(local_file_path):
        print(f"✗ File not found: {local_file_path}")
        return None
    
    # Construct URL with branch and directory path
    resource = f"{branch}/{remote_file_path}"
    url = f"{base_url}/api/repos/{namespace}/{repo_name}/file/{resource}"
    
    headers = {
        'Authorization': f'Bearer {api_key}'
    }
    
    # Prepare file for upload
    files = [
        ("file", (os.path.basename(local_file_path), open(local_file_path, 'rb')))
    ]
    
    payload = {
        'message': commit_message,
        'name': author_name,
        'email': author_email
    }
    
    response = requests.put(url, data=payload, files=files, headers=headers)
    
    # Close the file
    files[0][1][1].close()
    
    if response.status_code == 200:
        result = response.json()
        print(f"✓ File uploaded successfully")
        if 'commit' in result:
            print(f"  Commit ID: {result['commit'].get('id', 'N/A')}")
        return result
    else:
        print(f"✗ Failed: {response.status_code}")
        print(response.text)
        return None

# Usage
upload_file(
    base_url="https://hub.oxen.ai",
    api_key="your-api-key",
    namespace="your-username",
    repo_name="my-dataset",
    branch="main",
    local_file_path="./example.txt",
    remote_file_path="data/example.txt",
    commit_message="Add example file",
    author_name="Your Name",
    author_email="[email protected]"
)

Request Body (Multipart Form Data)

FieldTypeRequiredDescription
filefileYesThe file(s) to upload. Can be multiple files with the same field name
messagestringYesCommit message
namestringYesAuthor name
emailstringYesAuthor email
Note: You can upload multiple files in a single request by including multiple file fields with different filenames.

Response

{
  "commit": {
    "id": "abc123def456...",
    "message": "Add example file",
    "author": {
      "name": "Your Name",
      "email": "[email protected]"
    },
    "timestamp": "2026-01-08T21:28:00Z"
  },
  "file": {
    "path": "data/example.txt",
    "size": 1024,
    "hash": "sha256:..."
  }
}

Step 3: Create a Branch (Optional)

After uploading files, you can create additional branches from your main branch.

Endpoint

POST /api/repos/{namespace}/{repo_name}/branches

Example

import requests

def create_branch(base_url, api_key, namespace, repo_name, 
                  new_branch_name, from_branch):
    url = f"{base_url}/api/repos/{namespace}/{repo_name}/branches"
    
    headers = {
        'Authorization': f'Bearer {api_key}'
    }
    
    payload = {
        "new_name": new_branch_name,
        "from_name": from_branch
    }
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        print(f"✓ Branch '{new_branch_name}' created")
        return response.json()
    else:
        print(f"✗ Failed: {response.status_code}")
        print(response.text)
        return None

# Usage
create_branch(
    base_url="https://hub.oxen.ai",
    api_key="your-api-key",
    namespace="your-username",
    repo_name="my-dataset",
    new_branch_name="development",
    from_branch="main"
)

Request Body

FieldTypeRequiredDescription
new_namestringYesName of the new branch
from_namestringYesSource branch to create from

Response

{
  "name": "development",
  "commit_id": "abc123def456...",
  "created_at": "2026-01-08T21:28:00Z"
}

Complete Example

Here’s a complete Python script that ties everything together:
import os
import sys
import requests

# Configuration
SERVER_URL = "https://hub.oxen.ai"
API_KEY = "your-api-key-here"
NAMESPACE = "your-username"
REPO_NAME = "my-dataset"
USER_NAME = "Your Name"
USER_EMAIL = "[email protected]"
DESCRIPTION = "Example dataset created via HTTP API"

# File configuration
LOCAL_FILE_PATH = "./example.txt"
REMOTE_FILE_PATH = "data/example.txt"
COMMIT_MESSAGE = "Add file via HTTP API"
SOURCE_BRANCH = "main"

def main():
    print("=" * 70)
    print("Oxen File Upload Pipeline")
    print("=" * 70)
    
    base_url = SERVER_URL.rstrip('/')
    
    # Step 1: Create Repository
    print(f"\n[Step 1/2] Creating repository: {NAMESPACE}/{REPO_NAME}")
    create_repository(
        base_url=base_url,
        api_key=API_KEY,
        namespace=NAMESPACE,
        name=REPO_NAME,
        user_name=USER_NAME,
        user_email=USER_EMAIL,
        description=DESCRIPTION
    )
    
    # Step 2: Upload File
    print(f"\n[Step 2/2] Uploading file to '{SOURCE_BRANCH}' branch")
    print(f"           {LOCAL_FILE_PATH}{REMOTE_FILE_PATH}")
    upload_file(
        base_url=base_url,
        api_key=API_KEY,
        namespace=NAMESPACE,
        repo_name=REPO_NAME,
        branch=SOURCE_BRANCH,
        local_file_path=LOCAL_FILE_PATH,
        remote_file_path=REMOTE_FILE_PATH,
        commit_message=COMMIT_MESSAGE,
        author_name=USER_NAME,
        author_email=USER_EMAIL
    )
    
    print("\n" + "=" * 70)
    print("✓ Upload completed successfully!")
    print("=" * 70)
    print(f"\nRepository: {SERVER_URL}/{NAMESPACE}/{REPO_NAME}")
    print(f"File location: {SOURCE_BRANCH}{REMOTE_FILE_PATH}")
    print("=" * 70 + "\n")

if __name__ == '__main__':
    main()

Authentication

All API requests require authentication using a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEY

Getting an API Key

  1. Log in to your Oxen account at hub.oxen.ai
  2. Navigate to your account settings
  3. Generate a new API key

Advanced Usage

Uploading Multiple Files

You can upload multiple files in a single request by including multiple file fields:
import requests

namespace = "your-username"
repo_name = "my-dataset"
api_key = "your-api-key"
resource = "main/data"  # branch/directory

url = f"https://hub.oxen.ai/api/repos/{namespace}/{repo_name}/file/{resource}"

# Multiple files in one request
files = [
    ("file", ("file1.txt", open("./data/file1.txt", "rb"))),
    ("file", ("file2.csv", open("./data/file2.csv", "rb"))),
    ("file", ("photo.jpg", open("./images/photo.jpg", "rb")))
]

payload = {
    "email": "[email protected]",
    "message": "Add multiple files",
    "name": "Your Name"
}

headers = {"Authorization": f"Bearer {api_key}"}

response = requests.put(url, data=payload, files=files, headers=headers)

# Close all files
for _, (_, file_obj) in files:
    file_obj.close()

if response.status_code == 200:
    print("✓ All files uploaded successfully")
    print(response.json())
else:
    print(f"✗ Upload failed: {response.status_code}")
    print(response.text)
Or upload files one at a time:
files_to_upload = [
    ("./data/file1.txt", "data/file1.txt"),
    ("./data/file2.csv", "data/file2.csv"),
    ("./images/photo.jpg", "images/photo.jpg"),
]

for local_path, remote_path in files_to_upload:
    print(f"Uploading {local_path}...")
    upload_file(
        base_url=SERVER_URL,
        api_key=API_KEY,
        namespace=NAMESPACE,
        repo_name=REPO_NAME,
        branch="main",
        local_file_path=local_path,
        remote_file_path=remote_path,
        commit_message=f"Add {os.path.basename(local_path)}",
        author_name=USER_NAME,
        author_email=USER_EMAIL
    )

Uploading to Different Branches

# Upload to development branch
upload_file(
    base_url=SERVER_URL,
    api_key=API_KEY,
    namespace=NAMESPACE,
    repo_name=REPO_NAME,
    branch="development",  # Different branch
    local_file_path="./experiment.txt",
    remote_file_path="experiments/test1.txt",
    commit_message="Add experimental data",
    author_name=USER_NAME,
    author_email=USER_EMAIL
)

Organizing Files in Directories

Files are automatically organized based on the remote_file_path:
# Creates nested directory structure
upload_paths = {
    "./raw_data.csv": "datasets/raw/data.csv",
    "./processed.csv": "datasets/processed/data.csv",
    "./model.pt": "models/v1/checkpoint.pt",
    "./readme.md": "docs/README.md",
}

Next Steps