curl --request POST \
--url https://app.tryordinal.com/api/v1/uploads/prepare \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"filename": "product-photo.jpg",
"mimetype": "image/jpeg",
"size": 245678
}
'import requests
url = "https://app.tryordinal.com/api/v1/uploads/prepare"
payload = {
"filename": "product-photo.jpg",
"mimetype": "image/jpeg",
"size": 245678
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({filename: 'product-photo.jpg', mimetype: 'image/jpeg', size: 245678})
};
fetch('https://app.tryordinal.com/api/v1/uploads/prepare', 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://app.tryordinal.com/api/v1/uploads/prepare",
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' => 'product-photo.jpg',
'mimetype' => 'image/jpeg',
'size' => 245678
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://app.tryordinal.com/api/v1/uploads/prepare"
payload := strings.NewReader("{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://app.tryordinal.com/api/v1/uploads/prepare")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tryordinal.com/api/v1/uploads/prepare")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}"
response = http.request(request)
puts response.read_body{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "awaiting_upload",
"uploadUrl": "https://upload.example.com",
"params": "{\"auth\":{...},\"template_id\":\"...\"}",
"signature": "sha384:...",
"expiresAt": "2026-02-04T11:30:00.000Z",
"createdAt": "2026-02-04T10:30:00.000Z"
}{
"code": "BAD_REQUEST",
"message": "Bad Request",
"data": {
"errors": {
"publishAt": [
"Invalid date format"
],
"status": [
"Invalid enum value"
]
}
}
}{
"code": "UNAUTHORIZED",
"message": "Invalid or unauthorized API key"
}{
"code": "TOO_MANY_REQUESTS",
"message": "Rate limit of 100 requests per 60s exceeded. Quota resets in 45 seconds"
}Prepare a local file upload
Creates an upload job and returns signed credentials so you can POST a local file directly to the returned uploadUrl. After preparing, POST the file to uploadUrl as multipart form data with the returned params, signature, and file fields, then poll GET /uploads/{id} until status is ready.
See File uploads for a full walkthrough and curl examples.
Supported file types:
- Images: JPEG, PNG, GIF, WebP
- Videos: MP4, QuickTime (MOV)
File size limits:
- Images: 10 MB max
- GIFs: 15 MB max
- Videos: 350 MB max
The returned credentials are short-lived. Upload the file before expiresAt.
curl --request POST \
--url https://app.tryordinal.com/api/v1/uploads/prepare \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"filename": "product-photo.jpg",
"mimetype": "image/jpeg",
"size": 245678
}
'import requests
url = "https://app.tryordinal.com/api/v1/uploads/prepare"
payload = {
"filename": "product-photo.jpg",
"mimetype": "image/jpeg",
"size": 245678
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({filename: 'product-photo.jpg', mimetype: 'image/jpeg', size: 245678})
};
fetch('https://app.tryordinal.com/api/v1/uploads/prepare', 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://app.tryordinal.com/api/v1/uploads/prepare",
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' => 'product-photo.jpg',
'mimetype' => 'image/jpeg',
'size' => 245678
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://app.tryordinal.com/api/v1/uploads/prepare"
payload := strings.NewReader("{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://app.tryordinal.com/api/v1/uploads/prepare")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tryordinal.com/api/v1/uploads/prepare")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"product-photo.jpg\",\n \"mimetype\": \"image/jpeg\",\n \"size\": 245678\n}"
response = http.request(request)
puts response.read_body{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "awaiting_upload",
"uploadUrl": "https://upload.example.com",
"params": "{\"auth\":{...},\"template_id\":\"...\"}",
"signature": "sha384:...",
"expiresAt": "2026-02-04T11:30:00.000Z",
"createdAt": "2026-02-04T10:30:00.000Z"
}{
"code": "BAD_REQUEST",
"message": "Bad Request",
"data": {
"errors": {
"publishAt": [
"Invalid date format"
],
"status": [
"Invalid enum value"
]
}
}
}{
"code": "UNAUTHORIZED",
"message": "Invalid or unauthorized API key"
}{
"code": "TOO_MANY_REQUESTS",
"message": "Rate limit of 100 requests per 60s exceeded. Quota resets in 45 seconds"
}Authorizations
API key authentication. Generate an API key from your workspace settings.
Body
Response
Signed credentials for uploading the file
Response when a local file upload is prepared. Use uploadUrl, params, and signature to POST the file. See File uploads for the full multipart upload example.
Upload job ID. Use this to poll GET /uploads/{id}.
Initial status while Ordinal waits for the file POST.
awaiting_upload URL to POST the file to as multipart form data.
Signed upload params. Include verbatim as the params form field.
Signature for the params. Include verbatim as the signature form field.
Time after which the signed credentials are no longer valid.
Was this page helpful?