Skip to main content
POST
/
v1
/
files
/
init-upload
Initiate a direct multipart upload
curl --request POST \
  --url https://api.rendi.dev/v1/files/init-upload \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '
{
  "filename": "<string>",
  "size_bytes": 123,
  "is_private": false,
  "part_size": 10485760
}
'
import requests

url = "https://api.rendi.dev/v1/files/init-upload"

payload = {
"filename": "<string>",
"size_bytes": 123,
"is_private": False,
"part_size": 10485760
}
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({filename: '<string>', size_bytes: 123, is_private: false, part_size: 10485760})
};

fetch('https://api.rendi.dev/v1/files/init-upload', 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.rendi.dev/v1/files/init-upload",
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([
'filename' => '<string>',
'size_bytes' => 123,
'is_private' => false,
'part_size' => 10485760
]),
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.rendi.dev/v1/files/init-upload"

payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"size_bytes\": 123,\n \"is_private\": false,\n \"part_size\": 10485760\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.rendi.dev/v1/files/init-upload")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"size_bytes\": 123,\n \"is_private\": false,\n \"part_size\": 10485760\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.rendi.dev/v1/files/init-upload")

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 \"filename\": \"<string>\",\n \"size_bytes\": 123,\n \"is_private\": false,\n \"part_size\": 10485760\n}"

response = http.request(request)
puts response.read_body
{
  "file_id": "<string>",
  "part_size": 123,
  "upload_urls": [
    "<string>"
  ]
}
{
"detail": "Invalid authorization key"
}
{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}
Step 1 of 3 in the direct-upload flow. See the direct upload guide for the full flow and code samples.Bytes go directly to Rendi’s storage. Files up to 5 TB are supported.

Authorizations

X-API-KEY
string
header
required

Body

application/json
filename
string
required

The filename to store. Only alphanumeric characters, underscores, dashes, and dots are allowed.

Required string length: 1 - 255
Pattern: ^[a-zA-Z0-9_.\-]+$
Example:

"my_video.mp4"

size_bytes
integer
required

Total size of the file in bytes. Used to size the multipart chunks and verify quota up front. Maximum 5 TB.

Required range: x <= 5497558138880
Example:

104857600

is_private
boolean
default:false

If true, the uploaded file is placed in private storage and can only be downloaded via a presigned URL (request one by passing presigned_ttl_seconds on the files /get endpoint). Not available on trial plans.

Example:

false

part_size
integer | null

Requested per-part size in bytes. Optional. If not set, a sensible default is used. If the requested value is below 5 MB it's raised to 5 MB; if above 5 GB or too small for the file to fit in the allowed number of parts, it's clamped accordingly. The value actually used is returned in the response.

Required range: x > 0
Example:

10485760

Response

Multipart upload session created

file_id
string
required

Unique identifier for the uploaded file. Use it in complete-upload / abort-upload and to poll GET /files/{file_id}.

Example:

"987fcdeb-a89b-43d3-b456-789012345678"

part_size
integer
required

Byte size for every part except the last (which is the remainder). Split your file into chunks of exactly this size and PUT each chunk to the matching URL in upload_urls.

Example:

10485760

upload_urls
string[]
required

Presigned PUT URLs, one per part. Send part 1 to upload_urls[0], part 2 to upload_urls[1], and so on. Each response's ETag header must be sent back in complete-upload.