Skip to main content
Get a presigned URL for uploading files that will be used in template COPY steps. Files are uploaded to cloud storage and referenced in your template definition.

Endpoint

POST /v1/templates/files/upload-link

Request

Headers

Authorization: Bearer your_api_key_here
Content-Type: application/json

Request Body

{
  "files": [
    {
      "path": "config.json",
      "size": 1024,
      "hash": "sha256:abc123..."
    },
    {
      "path": "src/main.py",
      "size": 2048,
      "hash": "sha256:def456..."
    }
  ]
}
Parameters:
ParameterTypeRequiredDescription
filesarray✅ YesArray of file metadata objects
File Object:
FieldTypeRequiredDescription
pathstring✅ YesFile path (relative)
sizeinteger✅ YesFile size in bytes
hashstring✅ YesSHA256 hash of file content (format: sha256:...)

Response

Status Code: 200 OK
{
  "upload_urls": [
    {
      "path": "config.json",
      "upload_url": "https://storage.example.com/upload?token=...",
      "file_id": "file_abc123"
    },
    {
      "path": "src/main.py",
      "upload_url": "https://storage.example.com/upload?token=...",
      "file_id": "file_def456"
    }
  ]
}
Response Fields:
FieldTypeDescription
upload_urlsarrayArray of upload URL objects
Upload URL Object:
FieldTypeDescription
pathstringOriginal file path
upload_urlstringPresigned URL for uploading (valid for 1 hour)
file_idstringFile ID to use in COPY step

Examples

  • Python
  • JavaScript
import requests
import hashlib
import os

def upload_file_for_template(file_path, api_key):
    """Upload a file and get file_id for template"""
    # Read file and calculate hash
    with open(file_path, 'rb') as f:
        content = f.read()
        file_hash = hashlib.sha256(content).hexdigest()
        file_size = len(content)
    
    # Get upload URL
    response = requests.post(
        "https://api.hopx.dev/v1/templates/files/upload-link",
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        },
        json={
            "files": [{
                "path": os.path.basename(file_path),
                "size": file_size,
                "hash": f"sha256:{file_hash}"
            }]
        }
    )
    
    upload_info = response.json()["upload_urls"][0]
    
    # Upload file to presigned URL
    upload_response = requests.put(
        upload_info["upload_url"],
        data=content,
        headers={"Content-Type": "application/octet-stream"}
    )
    upload_response.raise_for_status()
    
    return upload_info["file_id"]

# Usage
file_id = upload_file_for_template("config.json", api_key)
print(f"File ID: {file_id}")

Using File IDs in Templates

After uploading files, use the file_id in your template COPY step:
{
  "type": "copy",
  "file_id": "file_abc123",
  "dest": "/workspace/config.json"
}
Or reference multiple files:
{
  "type": "copy",
  "file_ids": ["file_abc123", "file_def456"],
  "dest": "/workspace/"
}

Error Responses

400 Bad Request - Invalid file metadata
{
  "error": "Invalid file metadata",
  "message": "File hash must be in format 'sha256:...'"
}
401 Unauthorized - Invalid API key
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}

Notes

  • Upload URLs are valid for 1 hour
  • Files are deduplicated by hash - if a file with the same hash already exists, you’ll get the existing file_id
  • Maximum file size: 100 MB per file
  • Maximum files per request: 100 files

Next Steps