Working with the API
Uploads
Getting an image, a track or a mesh into a request, in three calls, with the bytes never passing through the API.
Many addresses take a file: an image to turn into a mesh, a mesh to split, a reference track, a clip to extend. This API sends JSON, so a file travels as a URL — one you already have, or one you make here — or, for our own 3D and video addresses, as the path of an upload.
A field's contract says which it accepts. In the address's OpenAPI document an asset field carries
format: "uri" when it takes a URL, contentEncoding: "base64" when it takes the bytes inline,
x-auray-encoding: "upload-path" when it takes the path an upload answered and nothing else, and
x-auray-encoding: "multipart" when the model only takes a file part — which this API does not
send, and refuses with unsupported_encoding rather than pretend.
#Three calls
Ask for somewhere to put it, naming the address the file is for. Everything else follows from
the address: which bucket holds it, which kinds of file its fields take, how large one may be, and
which key may put it there — the same scopes that may submit to that address. idempotency_key is
required — in the body, or as an Idempotency-Key header, the body's winning where both are sent — so a
retried request lands on the same object: the same path and read link, with a fresh upload_url.
curl -X POST https://api.auray.ai/v1/uploads \
-H "Authorization: Bearer $AURAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "address": "hitem3d/hi3d/split", "content_type": "model/gltf-binary", "idempotency_key": "chair-scan-3" }'import { readFile } from "node:fs/promises";
import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const upload = await auray.storage.upload({
address: "hitem3d/hi3d/split",
contentType: "model/gltf-binary",
data: await readFile("model.glb"),
idempotencyKey: "chair-scan-3",
});
// send_as names the field that takes the file, and whether it wants the path or the signed url
for (const { field, value } of upload.send_as ?? []) {
console.log(field, value === "read_url" ? upload.url : upload.path);
}from auray_client import Client
auray = Client() # reads AURAY_API_KEY
upload = auray.storage.upload_file("model.glb", address="hitem3d/hi3d/split", idempotency_key="chair-scan-3")
# send_as names the field that takes the file, and whether it wants the path or the signed url
for target in upload["send_as"] or []:
print(target["field"], upload["url"] if target["value"] == "read_url" else upload["path"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "upload_file",
"arguments": {
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"bytes_base64": "<base64>",
"idempotency_key": "chair-scan-3"
}
}
}const res = await fetch("https://api.auray.ai/v1/uploads", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"idempotency_key": "chair-scan-3"
}),
});
console.log(await res.json());import os, requests
r = requests.post(
"https://api.auray.ai/v1/uploads",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
json={
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"idempotency_key": "chair-scan-3"
},
)
r.raise_for_status()
print(r.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"idempotency_key": "chair-scan-3"
}`)
req, err := http.NewRequest("POST", "https://api.auray.ai/v1/uploads", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://api.auray.ai/v1/uploads");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"address" => "hitem3d/hi3d/split",
"content_type" => "model/gltf-binary",
"idempotency_key" => "chair-scan-3",
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
require "json"
uri = URI("https://api.auray.ai/v1/uploads")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
req["Content-Type"] = "application/json"
req.body = {
"address" => "hitem3d/hi3d/split",
"content_type" => "model/gltf-binary",
"idempotency_key" => "chair-scan-3"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String body = """
{
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"idempotency_key": "chair-scan-3"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.auray.ai/v1/uploads"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.auray.ai/v1/uploads");
var body = """
{
"address": "hitem3d/hi3d/split",
"content_type": "model/gltf-binary",
"idempotency_key": "chair-scan-3"
}
""";
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{
"object": "upload",
"upload_url": "https://…/upload/…",
"path": "86e97633-…/chair-scan-3.glb",
"bucket": "external-inputs",
"address": "hitem3d/hi3d/split",
"max_bytes": 209715200,
"expires_at": "2026-09-06T06:21:58.000Z",
"read": "https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit",
"send_as": [{ "field": "mesh_url", "kind": "mesh", "list": false, "value": "read_url" }],
"request_id": "…"
}send_as is every field of that address this file can go in. value says what to send there:
read_url is the url the third call answers, path is the path above. A file of a kind no field
of the address takes is refused with unknown_content_type, listing the types it does take; an
address none of whose fields takes a file is refused with upload_not_accepted.
Some fields carry a person: the recording a voice clone copies, the picture or clip a lip-sync or an
avatar makes speak or move, a person an edit puts into a clip, a reference clip whose own sound
becomes a voice. An upload there is taken once your account has accepted, one time, that you have the
right to the faces and voices you use — in the Auray app (Account → Privacy), or by sending
acceptance: {"real_people": "<words_version>"} with the request that first needs it — and is refused
403 acceptance_required until then, before anything is charged. That field's entry says so in
asks: the acceptance it asks and its words_version, the other fields whose presence beside it
makes the ask (when_also_sent, where an empty list means whatever else the request sends), and the
message the address's reference prints on the field. While using uploads that way is paused, the
entry also carries refused, and the request is answered 403 voice_sample_not_made_here or
403 likeness_not_made_here instead. A file one of your jobs made is always taken there.
Put the bytes there. Straight to storage, with the content type you declared — the API never
sees them, so there is no body-size limit on this side but the bucket's max_bytes.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: model/gltf-binary" \
--data-binary @chair-scan.glbAsk for the read URL, once the bytes are there — at the read address the first response
handed back. It names the address, which picks the bucket to sign from, and any scope that may upload
for that address — the kind it makes, or the older product name — reads back through it the account's
files of the kinds that address takes, which are often more than the kind it makes: a language model
takes images, video, audio and documents. assets:read alone does not: it fetches what a job made,
and an upload is something you sent. It is signed for at most 7 days, which is
longer than any job takes, and never past the upload itself, which is deleted 7 days
after it landed — so for what the upload has left: expires_at says when. Ask again for a fresh one while the upload is kept, and upload again
for a job you run after that.
curl "https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit" \
-H "Authorization: Bearer $AURAY_API_KEY"const res = await fetch("https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, requests
r = requests.get(
"https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
)
r.raise_for_status()
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("GET", "https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
],
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
uri = URI("https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.auray.ai/v1/uploads/86e97633-…/chair-scan-3.glb?address=hitem3d%2Fhi3d%2Fsplit");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{
"object": "upload",
"path": "86e97633-…/chair-scan-3.glb",
"bucket": "external-inputs",
"url": "https://…/sign/…",
"expires_at": "2026-09-13T04:22:05.000Z",
"request_id": "…"
}Asking before the bytes have landed answers 404 not_found; storage will not sign an object that
does not exist yet, and a read through an address signs no file of a kind that address does not take.
A read that names neither address nor product looks only in the buckets whose own scope your key
holds — the catalogue models' with external:write, then 3D's with 3d:write or threed:write. A
key without external:write, which is every key Account mints, is refused 403 insufficient_scope
there and told to name the address, unless the file is in 3D's bucket and the key holds 3d:write
or threed:write; so keep the query the read link carries.
Then put url in the field send_as named:
curl -X POST https://queue.auray.run/hitem3d/hi3d/split \
-H "Authorization: Bearer $AURAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "mesh_url": "https://…/sign/…" }'import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const job = await auray.queue.submit("hitem3d/hi3d/split", {
input: {
"mesh_url": "https://…/sign/…"
},
});
console.log(job.request_id, job.status);from auray_client import Client
auray = Client() # reads AURAY_API_KEY
job = auray.queue.submit(
"hitem3d/hi3d/split",
input={
"mesh_url": "https://…/sign/…"
},
)
print(job["request_id"], job["status"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "submit_job",
"arguments": {
"address": "hitem3d/hi3d/split",
"input": {
"mesh_url": "https://…/sign/…"
}
}
}
}const res = await fetch("https://queue.auray.run/hitem3d/hi3d/split", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
"mesh_url": "https://…/sign/…"
}),
});
console.log(await res.json());import os, requests
r = requests.post(
"https://queue.auray.run/hitem3d/hi3d/split",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
json={
"mesh_url": "https://…/sign/…"
},
)
r.raise_for_status()
print(r.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"mesh_url": "https://…/sign/…"
}`)
req, err := http.NewRequest("POST", "https://queue.auray.run/hitem3d/hi3d/split", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://queue.auray.run/hitem3d/hi3d/split");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"mesh_url" => "https://…/sign/…",
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
require "json"
uri = URI("https://queue.auray.run/hitem3d/hi3d/split")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
req["Content-Type"] = "application/json"
req.body = {
"mesh_url" => "https://…/sign/…"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String body = """
{
"mesh_url": "https://…/sign/…"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://queue.auray.run/hitem3d/hi3d/split"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://queue.auray.run/hitem3d/hi3d/split");
var body = """
{
"mesh_url": "https://…/sign/…"
}
""";
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");#A path, not a URL: our 3D and video addresses
auray-ai/hunyuan-3d/image-to-3d takes its photograph as image_path, and that field takes the
path the first call answered — as it is, with no read step; its send_as says "value": "path".
It never takes a URL: we do not fetch one you give us, and a path in another account's folder is
refused with image_required.
auray-ai/minimax-h3/text-to-video takes pictures the same way: first_frame_path, the picture a
clip opens on, or reference_image_paths, a list of up to nine that hold a subject — never both in
one request. Its uploads are stored as api-<idempotency_key>, and its read link answers only those.
A path in another account's folder, or one with nothing there, is refused with
reference_must_be_uploaded before any charge.
curl -X POST https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d \
-H "Authorization: Bearer $AURAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "image_path": "86e97633-…/chair-photo-1.png", "tier": "textured" }'import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const job = await auray.queue.submit("auray-ai/hunyuan-3d/image-to-3d", {
input: {
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
},
});
console.log(job.request_id, job.status);from auray_client import Client
auray = Client() # reads AURAY_API_KEY
job = auray.queue.submit(
"auray-ai/hunyuan-3d/image-to-3d",
input={
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
},
)
print(job["request_id"], job["status"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "submit_job",
"arguments": {
"address": "auray-ai/hunyuan-3d/image-to-3d",
"input": {
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
}
}
}
}const res = await fetch("https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
}),
});
console.log(await res.json());import os, requests
r = requests.post(
"https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
json={
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
},
)
r.raise_for_status()
print(r.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
}`)
req, err := http.NewRequest("POST", "https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"image_path" => "86e97633-…/chair-photo-1.png",
"tier" => "textured",
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
require "json"
uri = URI("https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
req["Content-Type"] = "application/json"
req.body = {
"image_path" => "86e97633-…/chair-photo-1.png",
"tier" => "textured"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String body = """
{
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://queue.auray.run/auray-ai/hunyuan-3d/image-to-3d");
var body = """
{
"image_path": "86e97633-…/chair-photo-1.png",
"tier": "textured"
}
""";
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");#Buckets and limits
The address picks the row; you never name a bucket.
product | For | Takes | Up to |
|---|---|---|---|
threed | Our 3D address's photograph, sent as image_path | image/jpeg, image/png, image/webp | 20 MB |
external | Any input to an address outside auray-ai/ — only the kinds its fields take | images, video, audio, meshes, archives | 200 MB |
| — | Our video address's pictures, sent as first_frame_path or reference_image_paths; reached through its address only | image/jpeg, image/png, image/webp | 25 MB |
The last column is the bucket's own ceiling, and it is the max_bytes the first call answers.
Uploads are yours: the path begins with your account id, and no other account can read or sign it.
#Address, not product
The first call used to name a product — threed, video or external — and the caller had to
know which bucket an address reads. product still works for every key it worked for, and every
response to it carries a Deprecation header and a Link to this section; send address instead.
A key minted with the kinds uses it too, which is what a client that can name only the product
needs: external takes such a key's files of the kinds some address of its kinds takes — an image
with any of them, a mesh with 3d:write — and so does its read link; a file of another kind is
refused 403 insufficient_scope, naming the scopes that would take it.
video is no longer offered: a picture for our video goes through its address, which stores it under a
name of its own and reads back only those. The product spelling answers only the keys that used it — one holding auray-ai-video:write,
or video:write beside external:write — for an upload there and for a read back with
?product=video. video:write without external:write — the video kind as Account mints it — is
refused 403 insufficient_scope there, and so is external:write alone.
#Or skip all of this
A public https:// URL works in any URL field as it is. Uploading is for
files that are not on the internet yet, or that you would rather not leave there. A path field is
the exception: image_path, first_frame_path and reference_image_paths take only an upload's path.
The desktop's composer does exactly these three calls when you add a file from your computer, and its Use in your code marks where the request reads what your own upload answers.