Artifact Storage API Reference
The OpenAI server provides a RESTful API for storing and retrieving generic artifacts (files). This API allows you to upload any type of file and retrieve it later using a unique identifier.
Authentication
The artifact API endpoints do not require authentication and are publicly accessible. In production environments, consider implementing authentication middleware as needed.
Content Types
The API supports any content type. Common examples include:
text/plain
- Text filesapplication/json
- JSON documentsimage/jpeg
,image/png
- Imagesapplication/pdf
- PDF documentsaudio/webm
,audio/wav
- Audio filesapplication/octet-stream
- Binary files
Endpoints
Upload Artifact
Uploads a new artifact to the server.
Request:
POST /artifact/
Headers:
Content-Type
(required): MIME type of the file being uploadedX-Original-Filename
(required): Original filename including extension
Request Body:
- Binary file data
Response:
Success (201 Created):
{
"artifactId": "7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf"
}
Response Headers:
Location
: URL where the artifact can be retrievedContent-Type
:application/json
Error Responses:
400 Bad Request:
Missing 'Content-Type' or 'X-Original-Filename' header
413 Payload Too Large:
Error saving file: http: request body too large
500 Internal Server Error:
Could not create file on server
Example:
curl -X POST http://localhost:8080/artifact/ \
-H "Content-Type: text/plain" \
-H "X-Original-Filename: example.txt" \
--data-binary @example.txt
Retrieve Artifact
Downloads an artifact by its unique identifier.
Request:
GET /artifact/{artifactId}
Path Parameters:
artifactId
(required): UUID of the artifact to retrieve
Response:
Success (200 OK):
- Returns the original file content as binary data
Response Headers:
Content-Type
: Original MIME type of the fileContent-Disposition
:inline; filename="original-filename.ext"
Content-Length
: Size of the file in bytesAccept-Ranges
:bytes
(supports range requests)Last-Modified
: Timestamp when the file was uploaded
Error Responses:
400 Bad Request:
Invalid artifact ID format
404 Not Found:
404 page not found
500 Internal Server Error:
Could not read artifact metadata
Corrupted artifact metadata
Example:
curl http://localhost:8080/artifact/7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf
Data Models
Artifact Metadata
Each uploaded artifact has associated metadata stored in a .meta.json
file:
{
"originalFilename": "example.txt",
"contentType": "text/plain",
"size": 1024,
"uploadTimestamp": "2025-09-19T12:01:11.277651Z"
}
Fields:
originalFilename
(string): The original name of the uploaded filecontentType
(string): MIME type of the filesize
(number): Size of the file in bytesuploadTimestamp
(string): ISO 8601 timestamp of when the file was uploaded
Configuration
The artifact storage behavior can be configured using environment variables:
ARTIFACT_PATH
: Directory where artifacts are stored (default:~/openaiserver/artifacts
)MAX_UPLOAD_SIZE
: Maximum file size in bytes (default:52428800
= 50MB)
File Storage
Storage Structure
Artifacts are stored using the following directory structure:
${ARTIFACT_PATH}/
├── 7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf # Binary file content
├── 7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf.meta.json # Metadata file
├── 123e4567-e89b-12d3-a456-426614174000 # Another file
└── 123e4567-e89b-12d3-a456-426614174000.meta.json # Its metadata
File Naming
- Artifact files: Named using the UUID (no extension)
- Metadata files: Named using the UUID +
.meta.json
suffix - UUIDs: Generated using UUID v4 standard (RFC 4122)
Security Considerations
File Size Limits
- Default maximum upload size: 50MB
- Configurable via
MAX_UPLOAD_SIZE
environment variable - Requests exceeding the limit return HTTP 413 (Payload Too Large)
File Type Validation
- The API accepts any content type
- Content type validation is based on the
Content-Type
header - No server-side file content inspection is performed
Path Traversal Protection
- Artifact IDs must be valid UUIDs
- Invalid UUID format returns HTTP 400 (Bad Request)
- File paths are constructed using secure
filepath.Join()
Storage Directory
- Default storage path uses user home directory
- Tilde (
~
) expansion is supported - Directory is created automatically with 0755 permissions
- Metadata files are created with 0644 permissions
Error Handling
Client Errors (4xx)
- 400 Bad Request: Invalid UUID format or missing required headers
- 404 Not Found: Artifact with the specified ID does not exist
- 413 Payload Too Large: File exceeds maximum upload size
Server Errors (5xx)
- 500 Internal Server Error: File system errors, metadata corruption, or server misconfiguration
Logging
All artifact operations are logged with structured logging:
INFO Artifact uploaded successfully artifactID=7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf filename=example.txt size=1024
DEBUG Artifact served artifactID=7f33ee3d-b589-4b3c-b8c8-a9a3ee04eacf filename=example.txt
ERROR Could not create artifact file error="permission denied" path=/artifacts/uuid
Rate Limiting
The artifact API does not implement built-in rate limiting. For production environments, consider implementing rate limiting at the reverse proxy level or using middleware.
CORS Support
The artifact API includes CORS headers to support web-based clients:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
Access-Control-Allow-Credentials: true
Integration Examples
JavaScript/Fetch API
// Upload file
const uploadFile = async (file) => {
const response = await fetch('/artifact/', {
method: 'POST',
headers: {
'Content-Type': file.type,
'X-Original-Filename': file.name
},
body: file
});
const result = await response.json();
return result.artifactId;
};
// Download file
const downloadFile = async (artifactId) => {
const response = await fetch(`/artifact/${artifactId}`);
return response.blob();
};
Python/Requests
import requests
# Upload file
def upload_file(file_path, content_type):
with open(file_path, 'rb') as f:
headers = {
'Content-Type': content_type,
'X-Original-Filename': os.path.basename(file_path)
}
response = requests.post('http://localhost:8080/artifact/',
headers=headers, data=f)
return response.json()['artifactId']
# Download file
def download_file(artifact_id, output_path):
response = requests.get(f'http://localhost:8080/artifact/{artifact_id}')
with open(output_path, 'wb') as f:
f.write(response.content)
Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
// Upload file
func uploadFile(filePath, contentType string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
req, err := http.NewRequest("POST", "http://localhost:8080/artifact/", file)
if err != nil {
return "", err
}
req.Header.Set("Content-Type", contentType)
req.Header.Set("X-Original-Filename", filepath.Base(filePath))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result map[string]string
json.NewDecoder(resp.Body).Decode(&result)
return result["artifactId"], nil
}
// Download file
func downloadFile(artifactID, outputPath string) error {
resp, err := http.Get(fmt.Sprintf("http://localhost:8080/artifact/%s", artifactID))
if err != nil {
return err
}
defer resp.Body.Close()
file, err := os.Create(outputPath)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, resp.Body)
return err
}
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.