File uploads
Upload with presigned OSS URLs or use one-step URL, multipart stream, and Base64 endpoints.
HopsAPI provides two upload families:
- Direct OSS upload for browsers, large files, and high concurrency. File bytes bypass the HopsAPI gateway.
- One-step compatibility endpoints for remote URLs, multipart file streams, and Base64. A successful request immediately returns a public
fileUrlsuitable for media inputs.
Every endpoint requires a HopsAPI API key through Authorization: Bearer sk-... or x-api-key. The three one-step endpoints create public temporary objects that are expected to be removed by the OSS lifecycle rule after 24 hours by default.
expiresAt is calculated from the gateway's OSS_TEMP_OBJECT_TTL_SEC setting. Operations must
configure a matching OSS lifecycle rule for public/tmp/; the API does not scan or delete objects
itself.
Method comparison
| Method | Endpoint | Best for | Default limit |
|---|---|---|---|
| Direct OSS | /api/v1/asset/get-presigned-url + /api/v1/asset/register | Large files, browsers, private objects | Controlled by OSS policy |
| URL upload | /api/file-url-upload | Importing a public remote file into the HopsAPI CDN | 100 MB |
| Stream upload | /api/file-stream-upload | Uploading a local file directly | 100 MB |
| Base64 upload | /api/file-base64-upload | Small files and JSON-only integrations | 10 MB decoded |
uploadPath and fileName are optional. Unsafe characters are sanitized, and the real object name includes a UUID, so an upload never overwrites an older object with the same name.
One-step response
All three compatibility endpoints return the same success structure:
{
"success": true,
"code": 200,
"msg": "文件上传成功",
"data": {
"fileId": "file_550e8400e29b41d4a716446655440000",
"fileName": "reference.png",
"originalName": "reference.png",
"fileSize": 245760,
"mimeType": "image/png",
"uploadPath": "images",
"fileUrl": "https://assets.example.com/public/tmp/42/images/...-reference.png",
"downloadUrl": "https://assets.example.com/public/tmp/42/images/...-reference.png",
"uploadTime": "2026-07-24T06:00:00.000Z",
"expiresAt": "2026-07-25T06:00:00.000Z"
}
}fileId has a stable identifier format for this response, but the current implementation does not create a queryable asset database record. Public temporary objects use the same URL for fileUrl and downloadUrl.
URL upload
/api/file-url-uploadDownloads a public HTTP(S) file and stores it under the current account's temporary public prefix.
{
"fileUrl": "https://example.com/reference.png",
"uploadPath": "images",
"fileName": "reference.png"
}| Field | Type | Required | Description |
|---|---|---|---|
fileUrl | string | Yes | Publicly reachable HTTP(S) file URL. |
uploadPath | string | No | Logical path such as images/references. At most eight sanitized segments are retained. |
fileName | string | No | Display file name. When omitted, it is derived from the final URL. |
curl https://hopsapi.com/api/file-url-upload \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileUrl": "https://example.com/reference.png",
"uploadPath": "images",
"fileName": "reference.png"
}'URL imports default to a 30-second timeout, five redirects, and 100 MB. Every resolution and redirect rejects localhost, private, loopback, link-local, reserved, credential-bearing, and otherwise non-public targets to reduce SSRF risk.
Stream upload
/api/file-stream-uploadUploads a local file using multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Local file, 100 MB by default. |
uploadPath | string | No | Logical path. |
fileName | string | No | Display file name. The multipart file name is used when omitted. |
curl https://hopsapi.com/api/file-stream-upload \
-H "Authorization: Bearer sk-YOUR_KEY" \
-F "file=@./reference.png" \
-F "uploadPath=images" \
-F "fileName=reference.png"Stream bytes pass through the HopsAPI gateway before being uploaded to OSS. Prefer direct OSS upload for large files or high concurrency.
Base64 upload
/api/file-base64-uploadUploads raw Base64 or a Data URL in a JSON request.
{
"base64Data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"uploadPath": "images",
"fileName": "reference.png"
}| Field | Type | Required | Description |
|---|---|---|---|
base64Data | string | Yes | Raw Base64 or data:<mime>;base64,...; 10 MB decoded by default. |
uploadPath | string | No | Logical path. |
fileName | string | No | Display name. When omitted, a random name is generated from the Data URL MIME type. |
curl https://hopsapi.com/api/file-base64-upload \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"base64Data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"uploadPath": "images",
"fileName": "reference.png"
}'Base64 increases request size by about 33%. Use stream or direct OSS upload for files larger than 10 MB.
Direct presigned OSS upload
The existing three-step flow remains unchanged and is still recommended for large files:
- Call
POST /api/v1/asset/get-presigned-urlwith file metadata and visibility. - Send the file bytes directly to the returned
signed_urlwith HTTPPUT. - Call
POST /api/v1/asset/registerwithobject_keyto verify the object and obtainfile_url.
1. Request an upload URL
/api/v1/asset/get-presigned-urlCreates an account-scoped object key and temporary presigned OSS upload URL.
{
"file_name": "report.pdf",
"content_type": "application/pdf",
"is_public": false
}| Field | Type | Required | Description |
|---|---|---|---|
file_name | string | Yes | Original name. Directory components are removed and unsafe characters replaced. |
content_type | string | Yes | MIME type used for the upload signature. |
is_public | boolean | Yes | true returns a public CDN URL; false returns a temporary signed download URL. |
Response:
{
"object_key": "private/tmp/42/550e8400-e29b-41d4-a716-446655440000-report.pdf",
"signed_url": "https://assets.example.com/private/tmp/42/...?OSSAccessKeyId=..."
}The upload URL expires after approximately ten minutes by default. Keep object_key for registration.
2. PUT the file
curl --request PUT "SIGNED_URL" \
--header "Content-Type: application/pdf" \
--upload-file ./report.pdfContent-Type must exactly match the content_type used to request the signature. Do not add the
HopsAPI Authorization header to the OSS request, and do not log or share signed URLs.
3. Register the object
/api/v1/asset/registerVerifies that the object belongs to the current account and exists, then returns its public or private access URL.
{
"object_key": "private/tmp/42/550e8400-e29b-41d4-a716-446655440000-report.pdf",
"name": "Quarterly report"
}Response:
{
"name": "Quarterly report",
"type": "application/pdf",
"file_url": "https://assets.example.com/private/tmp/42/...?OSSAccessKeyId=..."
}Public objects return an unauthenticated CDN URL. Private objects return a signed GET URL valid for approximately one hour by default. Call registration again with the same object_key to refresh a private URL.
Errors
One-step compatibility endpoints use:
{
"success": false,
"code": 413,
"msg": "文件超过大小限制",
"data": null
}| HTTP status | Meaning |
|---|---|
400 | Invalid body, Base64, URL, or missing required field |
401 | Missing, invalid, or inactive API key |
413 | Request body or file exceeds the endpoint limit |
502 | Remote download or OSS upload failed |
Validation, authentication, size, and upstream failures use the compatibility shape above. File endpoints do not use the LLM account limits or the retired shared per-key/per-IP allowance.
The existing presign and registration endpoints keep their OpenAI-compatible error object. OSS PUT failures are returned directly by OSS.