Multipart uploads
Upload a large file in parts, complete the storage upload with ordered ETags, and register its source URL.
Use multipart upload when a file is too large for a single transfer or individual parts need to be retried.
1. Create the upload
export LINGOPAL_API_KEY="your-api-key"
curl -X POST "https://api.lingopal.ai/v2/storage/uploads" \
-H "X-API-Key: $LINGOPAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_ext": "mp4",
"file_size": 2147483648
}'Authorization
APIKeyHeader In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/v2/storage/uploads" \ -H "Content-Type: application/json" \ -d '{ "file_ext": "mp4" }'{ "source_url": "https://cdn.example.com/presigned_upload/user_123/source.mp4", "file_path": "presigned_upload/user_123/source.mp4", "upload_id": "2~example-upload-id", "upload_urls": [ { "part_number": 1, "upload_url": "https://example-bucket.s3.amazonaws.com/presigned_upload/user_123/source.mp4?partNumber=1&X-Amz-Signature=..." } ], "method": "PUT", "headers": { "Content-Type": "video/mp4" }}Use the API Reference entry for createStorageUpload for exact request payload and response fields.
Save file_path, upload_id, source_url, and every item in upload_urls.
2. Upload every part
PUT each byte range to its corresponding presigned URL. Record the returned ETag and part number. Failed parts can be retried independently while their presigned URLs remain valid.
3. Resume an interrupted upload
An interrupted transfer does not restart from zero. The multipart session stays open on S3, so you can list the parts already confirmed and fetch fresh presigned URLs for the remaining parts:
export LINGOPAL_API_KEY="your-api-key"
curl -X POST "https://api.lingopal.ai/v2/storage/uploads/parts" \
-H "X-API-Key: $LINGOPAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_path": "presigned_upload/user/source.mp4",
"upload_id": "upload-id",
"file_size": 2147483648
}'The response contains parts (confirmed part numbers with ETags and sizes), upload_urls (fresh presigned URLs for every part), part_size_bytes, and source_url.
- PUT only the parts missing from
parts, using their entries inupload_urls. - Complete the upload with the combined ETags as described below.
An unknown or expired upload_id returns 404 and the session must be recreated with createStorageUpload. Uploads owned by another user return 403.
4. Complete the upload
Send the saved file_path, upload_id, and ETags in part order:
export LINGOPAL_API_KEY="your-api-key"
curl -X POST "https://api.lingopal.ai/v2/storage/uploads/complete" \
-H "X-API-Key: $LINGOPAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_path": "presigned_upload/user/source.mp4",
"upload_id": "upload-id",
"etags": [
{"part_number": 1, "etag": "etag-1"},
{"part_number": 2, "etag": "etag-2"}
]
}'Authorization
APIKeyHeader In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/v2/storage/uploads/complete" \ -H "Content-Type: application/json" \ -d '{ "file_path": "presigned_upload/user_123/source.mp4", "upload_id": "2~example-upload-id", "etags": [ { "part_number": 1, "etag": "\\"9b2cf535f27731c974343645a3985328\\"" }, { "part_number": 2, "etag": "\\"2a1fd1f7bc39b3868d2a8f6fb50f6a7d\\"" } ] }'{ "file_path": "presigned_upload/user_123/source.mp4", "source_url": "https://cdn.example.com/presigned_upload/user_123/source.mp4"}Use the API Reference entry for completeStorageUpload for response and validation details.
5. Register the source
Register the source_url with POST /v2/jobs/register to receive a job_id. Storage completion alone does not start processing.