curl --request POST \
--url https://api.orion.file.ai/prod/v1/files/upload/multipart/complete \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"id": "upload_abc123xyz",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"parts": [
{
"partNumber": 1,
"eTag": "\"etag1\""
},
{
"partNumber": 2,
"eTag": "\"etag2\""
}
]
}
'import requests
url = "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete"
payload = {
"id": "upload_abc123xyz",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"parts": [
{
"partNumber": 1,
"eTag": "\"etag1\""
},
{
"partNumber": 2,
"eTag": "\"etag2\""
}
]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'upload_abc123xyz',
key: 'org_123/workspace_456/device/file_abc/document.pdf',
parts: [{partNumber: 1, eTag: '"etag1"'}, {partNumber: 2, eTag: '"etag2"'}]
})
};
fetch('https://api.orion.file.ai/prod/v1/files/upload/multipart/complete', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'upload_abc123xyz',
'key' => 'org_123/workspace_456/device/file_abc/document.pdf',
'parts' => [
[
'partNumber' => 1,
'eTag' => '"etag1"'
],
[
'partNumber' => 2,
'eTag' => '"etag2"'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete"
payload := strings.NewReader("{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orion.file.ai/prod/v1/files/upload/multipart/complete")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orion.file.ai/prod/v1/files/upload/multipart/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"location": "https://s3.amazonaws.com/bucket/org_123/workspace_456/device/file_abc/document.pdf",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"etag": "\"abc123def456-2\"",
"success": true
}Complete a multipart upload
Complete a multipart upload after all parts have been uploaded to S3.
After uploading all parts using the presigned URLs from the initiate endpoint, call this endpoint with the ID, key, and all part ETags to finalize the upload.
The input should contain:
id: the ID from the multipart upload initiation (previously called uploadId)key: the S3 key from the multipart upload initiationparts: array of objects with partNumber and eTag for each uploaded part
curl --request POST \
--url https://api.orion.file.ai/prod/v1/files/upload/multipart/complete \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"id": "upload_abc123xyz",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"parts": [
{
"partNumber": 1,
"eTag": "\"etag1\""
},
{
"partNumber": 2,
"eTag": "\"etag2\""
}
]
}
'import requests
url = "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete"
payload = {
"id": "upload_abc123xyz",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"parts": [
{
"partNumber": 1,
"eTag": "\"etag1\""
},
{
"partNumber": 2,
"eTag": "\"etag2\""
}
]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'upload_abc123xyz',
key: 'org_123/workspace_456/device/file_abc/document.pdf',
parts: [{partNumber: 1, eTag: '"etag1"'}, {partNumber: 2, eTag: '"etag2"'}]
})
};
fetch('https://api.orion.file.ai/prod/v1/files/upload/multipart/complete', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'upload_abc123xyz',
'key' => 'org_123/workspace_456/device/file_abc/document.pdf',
'parts' => [
[
'partNumber' => 1,
'eTag' => '"etag1"'
],
[
'partNumber' => 2,
'eTag' => '"etag2"'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orion.file.ai/prod/v1/files/upload/multipart/complete"
payload := strings.NewReader("{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orion.file.ai/prod/v1/files/upload/multipart/complete")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orion.file.ai/prod/v1/files/upload/multipart/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"upload_abc123xyz\",\n \"key\": \"org_123/workspace_456/device/file_abc/document.pdf\",\n \"parts\": [\n {\n \"partNumber\": 1,\n \"eTag\": \"\\\"etag1\\\"\"\n },\n {\n \"partNumber\": 2,\n \"eTag\": \"\\\"etag2\\\"\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"location": "https://s3.amazonaws.com/bucket/org_123/workspace_456/device/file_abc/document.pdf",
"key": "org_123/workspace_456/device/file_abc/document.pdf",
"etag": "\"abc123def456-2\"",
"success": true
}How It Works
1. Upload All Parts
2. Collect ETags
3. Complete Upload
Request Parameters
Request Body
The request body must contain a JSON object with the following properties:| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | The ID from the multipart upload initiation (previously called uploadId) |
| key | string | Yes | The S3 key from the multipart upload initiation |
| parts | array | Yes | Array of objects with partNumber and eTag for each uploaded part |
Parts Array Structure
Each object in theparts array should contain:
| Property | Type | Required | Description |
|---|---|---|---|
| partNumber | number | Yes | Sequential part number (1, 2, 3, …) |
| eTag | string | Yes | ETag value from the part upload response |
Complete Workflow Example
- Initiate Upload: Call
/prod/v1/files/upload/multipartto get presigned URLs - Upload Parts: Use PUT requests to upload each part to its presigned URL
- Complete Upload: Call this endpoint with all part ETags to finalize
Idempotency-Key request header so a retry
cannot apply the change twice. See
Idempotent requests.Authorizations
API key for authentication
Headers
Optional opaque key (max 255 chars, UUIDv4 recommended) making this request idempotent for 24h: a retry with the same key and body replays the original response with Idempotent-Replayed: true.
Body
ID from the multipart upload initiation
"upload_abc123xyz"
S3 key from the multipart upload initiation
"org_123/workspace_456/device/file_abc/document.pdf"
Array of completed parts with part numbers and ETags
Show child attributes
Show child attributes
[
{ "partNumber": 1, "eTag": "\"etag1\"" },
{ "partNumber": 2, "eTag": "\"etag2\"" }
]
Response
Multipart upload completed successfully