File Transfer
Transfer files between local storage, object storage, and sandboxes
You can copy files between a Lybic sandbox instance and external storage, which is helpful for uploading datasets, scripts, or downloading result files.
API Endpoint
POST /api/orgs/{orgId}/sandboxes/{sandboxId}/file/copyRequest format
Basic request structure
curl -X POST "https://api.lybic.cn/api/orgs/{orgId}/sandboxes/{sandboxId}/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"files": [
{
"id": "unique-identifier",
"src": { ... },
"dest": { ... }
}
]
}'import asyncio
from lybic import LybicClient, LybicAuth
from lybic.dto import (
SandboxFileCopyRequestDto,
FileCopyItem,
SandboxFileLocation,
HttpGetLocation
)
async def main():
async with LybicClient(
LybicAuth(
org_id="ORG-xxxx",
api_key="lysk-xxxxxxxxxxx",
endpoint="https://api.lybic.cn/"
)
) as client:
response = await client.sandbox.copy_files(
"SBX-xxxx",
SandboxFileCopyRequestDto(files=[
FileCopyItem(
id="unique-identifier",
src=HttpGetLocation(url="https://example.com/file.txt"),
dest=SandboxFileLocation(path="/home/agent/file.txt")
)
])
)
print("Copy result:", response)
if __name__ == "__main__":
asyncio.run(main())import { LybicClient } from '@lybic/core'
const lybic = new LybicClient({
baseUrl: 'https://api.lybic.cn',
orgId: 'ORG-xxxx',
apiKey: 'lysk-your-api-key-here',
})
const result = await lybic.copyFilesWithSandbox('SBX-xxxx', {
files: [
{
id: 'unique-identifier',
src: {
type: 'httpGetLocation',
url: 'https://example.com/file.txt',
},
dest: {
type: 'sandboxFileLocation',
path: '/home/agent/file.txt',
},
},
],
})
console.log('Copy result:', result.data)package main
import (
"context"
"fmt"
"github.com/lybic/lybic-sdk-go"
)
func main() {
ctx := context.Background()
client, _ := lybic.NewClient(nil)
copyDto := lybic.SandboxFileCopyRequestDto{
Files: []lybic.SandboxFileCopyRequestDtoFiles{
{
Src: map[string]string{
"type": "httpGetLocation",
"url": "https://example.com/file.txt",
},
Dest: map[string]any{
"type": "sandboxFileLocation",
"path": "/home/agent/file.txt",
},
},
},
}
result, err := client.CopyFilesWithSandbox(ctx, "SBX-xxxx", copyDto)
if err != nil {
fmt.Println("Error copying file:", err)
return
}
fmt.Printf("Copy result: %+v\n", result)
}Request body parameters
files(array, required): List of file copy operations, at least one entryid(string, optional): Caller-defined identifier used to correlate results in the responsesrc(object, required): Source location of the filedest(object, required): Destination location for the file
Supported location types
1. SandboxFileLocation - File path inside the sandbox
{
"type": "sandboxFileLocation",
"path": "/home/agent/file.txt"
}2. HttpGetLocation - HTTP GET download
{
"type": "httpGetLocation",
"url": "https://example.com/file.txt",
"headers": {
"Authorization": "Bearer token",
"X-Custom-Header": "value"
}
}3. HttpPutLocation - HTTP PUT upload
{
"type": "httpPutLocation",
"url": "https://storage.example.com/file.txt",
"headers": {
"Content-Type": "application/octet-stream"
}
}4. HttpPostFormLocation - HTTP POST multipart form upload
{
"type": "httpPostFormLocation",
"url": "https://api.example.com/upload",
"form": {
"key": "value",
"policy": "eyJleHBpcmF0aW9uIjoi..."
},
"fileField": "file",
"headers": {
"X-Custom-Header": "value"
}
}Response format
{
"results": [
{
"id": "unique-identifier",
"success": true,
"error": "error message if failed"
}
]
}Usage scenarios
1. Transfer between local files and object storage
1.1 Upload a local file to object storage (using PUT)
# Step 1: Obtain a pre-signed PUT URL (example uses MinIO)
# This is typically generated via the object storage SDK or API
# Step 2: Upload the file via the pre-signed URL
curl -X PUT "https://storage.example.com/presigned-url" \
--upload-file local-file.txt1.2 Download from object storage to a local file (using GET)
# Step 1: Obtain a pre-signed GET URL (example uses MinIO)
# This is typically generated via the object storage SDK or API
# Step 2: Download the file
curl -X GET "https://storage.example.com/presigned-url" \
-o downloaded-file.txt2. Transfer between local files and a sandbox (via object storage)
2.1 Upload a local file to the sandbox
Flow: Local file → Object storage → Sandbox
# Step 1: Upload the local file to object storage
curl -X PUT "https://storage.example.com/presigned-put-url" \
--upload-file local-data.json
# Step 2: Capture the download URL (pre-signed GET URL)
DOWNLOAD_URL="https://storage.example.com/presigned-get-url"
# Step 3: Download the file into the sandbox
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "upload-1",
"src": {
"type": "httpGetLocation",
"url": "'"$DOWNLOAD_URL"'"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/data.json"
}
}
]
}'2.2 Download a sandbox file to local storage
Flow: Sandbox → Object storage → Local file
# Step 1: Obtain a pre-signed PUT URL for uploading
UPLOAD_URL="https://storage.example.com/presigned-put-url"
# Step 2: Upload the sandbox file to object storage
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "download-1",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/output.txt"
},
"dest": {
"type": "httpPutLocation",
"url": "'"$UPLOAD_URL"'"
}
}
]
}'
# Step 3: Download the file from object storage to local storage
curl -X GET "https://storage.example.com/presigned-get-url" \
-o local-output.txt3. Transfer between sandboxes and object storage
3.1 Download from object storage to the sandbox
# Single file download
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "download-dataset",
"src": {
"type": "httpGetLocation",
"url": "https://storage.example.com/datasets/training-data.csv"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/datasets/training-data.csv"
}
}
]
}'import asyncio
from lybic import LybicClient, LybicAuth
from lybic.dto import (
SandboxFileCopyRequestDto,
FileCopyItem,
SandboxFileLocation,
HttpGetLocation
)
async def main():
async with LybicClient(
LybicAuth(
org_id="ORG-xxx",
api_key="lysk-xxxxxxxxx",
endpoint="https://api.lybic.cn/"
)
) as client:
response = await client.sandbox.copy_files(
"BOX-xxx",
SandboxFileCopyRequestDto(files=[
FileCopyItem(
id="download-dataset",
src=HttpGetLocation(
url="https://storage.example.com/datasets/training-data.csv"
),
dest=SandboxFileLocation(
path="/home/agent/datasets/training-data.csv"
)
)
])
)
for result in response.results:
if result.success:
print(f"✓ File downloaded (id: {result.id})")
else:
print(f"✗ Download failed (id: {result.id}): {result.error}")
if __name__ == "__main__":
asyncio.run(main())import { LybicClient } from '@lybic/core'
const lybic = new LybicClient({
baseUrl: 'https://api.lybic.cn',
orgId: 'ORG-xxx',
apiKey: 'lysk-xxxxxxxxx',
})
const result = await lybic.copyFilesWithSandbox('BOX-xxx', {
files: [
{
id: 'download-dataset',
src: {
type: 'httpGetLocation',
url: 'https://storage.example.com/datasets/training-data.csv',
},
dest: {
type: 'sandboxFileLocation',
path: '/home/agent/datasets/training-data.csv',
},
},
],
})
result.data?.results?.forEach((r) => {
if (r.success) {
console.log(`✓ File downloaded (id: ${r.id})`)
} else {
console.log(`✗ Download failed (id: ${r.id}): ${r.error}`)
}
})package main
import (
"context"
"fmt"
"github.com/lybic/lybic-sdk-go"
)
func main() {
ctx := context.Background()
client, _ := lybic.NewClient(nil)
copyDto := lybic.SandboxFileCopyRequestDto{
Files: []lybic.SandboxFileCopyRequestDtoFiles{
{
Id: "download-dataset",
Src: map[string]string{
"type": "httpGetLocation",
"url": "https://storage.example.com/datasets/training-data.csv",
},
Dest: map[string]any{
"type": "sandboxFileLocation",
"path": "/home/agent/datasets/training-data.csv",
},
},
},
}
result, err := client.CopyFilesWithSandbox(ctx, "BOX-xxx", copyDto)
if err != nil {
fmt.Println("Error copying files:", err)
return
}
for _, r := range result.Results {
if r.Success {
fmt.Printf("✓ File downloaded (id: %s)\n", r.Id)
} else {
fmt.Printf("✗ Download failed (id: %s): %s\n", r.Id, r.Error)
}
}
}3.2 Upload from the sandbox to object storage
# Single file upload
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "upload-result",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/results/model-output.pkl"
},
"dest": {
"type": "httpPutLocation",
"url": "https://storage.example.com/presigned-put-url"
}
}
]
}'import asyncio
from lybic import LybicClient, LybicAuth
from lybic.dto import (
SandboxFileCopyRequestDto,
FileCopyItem,
SandboxFileLocation,
HttpPutLocation
)
async def main():
async with LybicClient(
LybicAuth(
org_id="ORG-xxx",
api_key="lysk-xxxxxxxxx",
endpoint="https://api.lybic.cn/"
)
) as client:
response = await client.sandbox.copy_files(
"BOX-xxx",
SandboxFileCopyRequestDto(files=[
FileCopyItem(
id="upload-result",
src=SandboxFileLocation(
path="/home/agent/results/model-output.pkl"
),
dest=HttpPutLocation(
url="https://storage.example.com/presigned-put-url"
)
)
])
)
for result in response.results:
if result.success:
print(f"✓ File uploaded (id: {result.id})")
else:
print(f"✗ Upload failed (id: {result.id}): {result.error}")
if __name__ == "__main__":
asyncio.run(main())import { LybicClient } from '@lybic/core'
const lybic = new LybicClient({
baseUrl: 'https://api.lybic.cn',
orgId: 'ORG-xxx',
apiKey: 'lysk-xxxxxxxxx',
})
const result = await lybic.copyFilesWithSandbox('BOX-xxx', {
files: [
{
id: 'upload-result',
src: {
type: 'sandboxFileLocation',
path: '/home/agent/results/model-output.pkl',
},
dest: {
type: 'httpPutLocation',
url: 'https://storage.example.com/presigned-put-url',
},
},
],
})
result.data?.results?.forEach((r) => {
if (r.success) {
console.log(`✓ File uploaded (id: ${r.id})`)
} else {
console.log(`✗ Upload failed (id: ${r.id}): ${r.error}`)
}
})package main
import (
"context"
"fmt"
"github.com/lybic/lybic-sdk-go"
)
func main() {
ctx := context.Background()
client, _ := lybic.NewClient(nil)
copyDto := lybic.SandboxFileCopyRequestDto{
Files: []lybic.SandboxFileCopyRequestDtoFiles{
{
Id: "upload-result",
Src: map[string]string{
"type": "sandboxFileLocation",
"path": "/home/agent/results/model-output.pkl",
},
Dest: map[string]any{
"type": "httpPutLocation",
"url": "https://storage.example.com/presigned-put-url",
},
},
},
}
result, err := client.CopyFilesWithSandbox(ctx, "BOX-xxx", copyDto)
if err != nil {
fmt.Println("Error copying files:", err)
return
}
for _, r := range result.Results {
if r.Success {
fmt.Printf("✓ File uploaded (id: %s)\n", r.Id)
} else {
fmt.Printf("✗ Upload failed (id: %s): %s\n", r.Id, r.Error)
}
}
}Refer to the full end-to-end example: Python SDK
4. Copying files within the sandbox
Copy files inside the sandbox (source and destination are both sandbox paths):
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "copy-config",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/config/template.yaml"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/config/production.yaml"
}
}
]
}'import asyncio
from lybic import LybicClient, LybicAuth
from lybic.dto import (
SandboxFileCopyRequestDto,
FileCopyItem,
SandboxFileLocation
)
async def main():
async with LybicClient(
LybicAuth(
org_id="ORG-xxx",
api_key="lysk-xxxxxxxxx",
endpoint="https://api.lybic.cn/"
)
) as client:
response = await client.sandbox.copy_files(
"BOX-xxx",
SandboxFileCopyRequestDto(files=[
FileCopyItem(
id="copy-config",
src=SandboxFileLocation(path="/home/agent/config/template.yaml"),
dest=SandboxFileLocation(path="/home/agent/config/production.yaml")
)
])
)
print("Copy result:", response)
if __name__ == "__main__":
asyncio.run(main())import { LybicClient } from '@lybic/core'
const lybic = new LybicClient({
baseUrl: 'https://api.lybic.cn',
orgId: 'ORG-xxx',
apiKey: 'lysk-xxxxxxxxx',
})
const result = await lybic.copyFilesWithSandbox('BOX-xxx', {
files: [
{
id: 'copy-config',
src: {
type: 'sandboxFileLocation',
path: '/home/agent/config/template.yaml',
},
dest: {
type: 'sandboxFileLocation',
path: '/home/agent/config/production.yaml',
},
},
],
})
console.log('Copy result:', result.data)package main
import (
"context"
"fmt"
"github.com/lybic/lybic-sdk-go"
)
func main() {
ctx := context.Background()
client, _ := lybic.NewClient(nil)
copyDto := lybic.SandboxFileCopyRequestDto{
Files: []lybic.SandboxFileCopyRequestDtoFiles{
{
Id: "copy-config",
Src: map[string]string{
"type": "sandboxFileLocation",
"path": "/home/agent/config/template.yaml",
},
Dest: map[string]any{
"type": "sandboxFileLocation",
"path": "/home/agent/config/production.yaml",
},
},
},
}
result, err := client.CopyFilesWithSandbox(ctx, "BOX-xxx", copyDto)
if err != nil {
fmt.Println("Error copying files:", err)
return
}
fmt.Printf("Copy result: %+v\n", result)
}5. Downloading files into specific sandbox paths (download helper)
5.1 Download from a public URL
# Download a public file
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "download-public-file",
"src": {
"type": "httpGetLocation",
"url": "https://raw.githubusercontent.com/example/repo/main/data.json"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/downloads/data.json"
}
}
]
}'5.2 Download from an authenticated URL
# Download using custom headers (e.g., private storage or APIs)
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "download-private-file",
"src": {
"type": "httpGetLocation",
"url": "https://api.example.com/files/dataset.csv",
"headers": {
"Authorization": "Bearer your-token-here",
"X-API-Key": "your-api-key"
}
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/data/dataset.csv"
}
}
]
}'Bulk file transfers
Download multiple files into the sandbox
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "file-1",
"src": {
"type": "httpGetLocation",
"url": "https://storage.example.com/file1.txt"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/file1.txt"
}
},
{
"id": "file-2",
"src": {
"type": "httpGetLocation",
"url": "https://storage.example.com/file2.json"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/file2.json"
}
},
{
"id": "file-3",
"src": {
"type": "httpGetLocation",
"url": "https://storage.example.com/file3.csv"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/data/file3.csv"
}
}
]
}'Mixed-direction bulk transfers
Upload and download multiple files within a single request:
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "download-input",
"src": {
"type": "httpGetLocation",
"url": "https://storage.example.com/input-data.csv"
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/input.csv"
}
},
{
"id": "upload-result",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/output.json"
},
"dest": {
"type": "httpPutLocation",
"url": "https://storage.example.com/presigned-put-url-1"
}
},
{
"id": "upload-logs",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/logs/process.log"
},
"dest": {
"type": "httpPutLocation",
"url": "https://storage.example.com/presigned-put-url-2"
}
}
]
}'Response examples
Success response:
{
"results": [
{
"id": "download-input",
"success": true
},
{
"id": "upload-result",
"success": true
},
{
"id": "upload-logs",
"success": true
}
]
}Partial failure response:
{
"results": [
{
"id": "file-1",
"success": true
},
{
"id": "file-2",
"success": false,
"error": "Failed to download file: 404 Not Found"
},
{
"id": "file-3",
"success": true
}
]
}Using POST forms for uploads
Some object storage providers (such as AWS S3) require uploads via POST forms:
# Upload from the sandbox using a POST form
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "form-upload",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/report.pdf"
},
"dest": {
"type": "httpPostFormLocation",
"url": "https://s3.amazonaws.com/your-bucket",
"form": {
"key": "uploads/report.pdf",
"AWSAccessKeyId": "YOUR_ACCESS_KEY",
"policy": "BASE64_ENCODED_POLICY",
"signature": "CALCULATED_SIGNATURE"
},
"fileField": "file"
}
}
]
}'Optional request header configuration
Common header examples
1. Authentication header
{
"type": "httpGetLocation",
"url": "https://api.example.com/file",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}2. API key authentication
{
"type": "httpGetLocation",
"url": "https://api.example.com/file",
"headers": {
"X-API-Key": "your-api-key-here"
}
}3. Content type configuration
{
"type": "httpPutLocation",
"url": "https://storage.example.com/file",
"headers": {
"Content-Type": "application/json"
}
}4. Custom header combinations
{
"type": "httpGetLocation",
"url": "https://api.example.com/file",
"headers": {
"Authorization": "Bearer token",
"X-Request-ID": "unique-request-id",
"User-Agent": "Lybic-Agent/1.0",
"Accept": "application/octet-stream"
}
}Full example: custom headers
curl -X POST "https://api.lybic.cn/api/orgs/ORG-xxx/sandboxes/BOX-xxx/file/copy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer lysk-xxxxxxxxx" \
-d '{
"files": [
{
"id": "authenticated-download",
"src": {
"type": "httpGetLocation",
"url": "https://secure-api.example.com/protected/file.dat",
"headers": {
"Authorization": "Bearer secure-token-12345",
"X-Client-ID": "client-id",
"X-Request-ID": "req-abc-123"
}
},
"dest": {
"type": "sandboxFileLocation",
"path": "/home/agent/secure/file.dat"
}
},
{
"id": "authenticated-upload",
"src": {
"type": "sandboxFileLocation",
"path": "/home/agent/output/result.json"
},
"dest": {
"type": "httpPutLocation",
"url": "https://storage.example.com/upload-endpoint",
"headers": {
"Content-Type": "application/json",
"X-Upload-Token": "upload-token-xyz",
"X-Checksum": "md5-hash-value"
}
}
}
]
}'Best practices
- Use unique IDs: Assign each file operation a unique
idto track results in bulk requests - Handle errors: Always inspect the
successflag anderrormessage in the response - Pre-signed URL expiry: Ensure pre-signed URLs have enough validity (recommend at least 1 hour)
- Batch operations: Group multiple files in the same request whenever possible for efficiency
- Header security: Avoid hard-coding sensitive values in headers; use environment variables or secure storage
- Path validation: Ensure the sandbox destination path exists or create necessary parent directories
- Large file transfers: For large files, consider streaming or chunked uploads
Common errors
| Error | Cause | Resolution |
|---|---|---|
| 404 Not Found | URL does not exist or has expired | Verify the URL and regenerate the pre-signed URL |
| 403 Forbidden | Insufficient permissions or authentication failed | Verify authorization headers and permissions |
| 400 Bad Request | Incorrect request format | Validate the JSON payload and required fields |
| File not found in sandbox | Source file is missing inside the sandbox | Confirm the sandbox path is correct |
| Network timeout | Network issue or file is too large | Increase timeout or transfer in chunks |