# Set a unique key once per new action; persist it and reuse it for every retry.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
: "${REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/files' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15" \
-H "Idempotency-Key: $REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
--data-raw '{
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}'import { env, exit } from "node:process";
// Set a unique key once per new action; persist it and reuse it for every retry.
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const idempotencyKey = env.REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY;
if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/files", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
# Set a unique key once per new action; persist it and reuse it for every retry.
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
idempotencyKey = os.environ["REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY"]
if not idempotencyKey:
raise ValueError("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
}
data = json.dumps({
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4",
}).encode("utf-8")
request = Request("https://app.reflections.ai/v1/files",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
// Set a unique key once per new action; persist it and reuse it for every retry.
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
idempotencyKey := os.Getenv("REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY")
if idempotencyKey == "" {
panic("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")
}
body := strings.NewReader(`{
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/files", body)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
request.Header.Set("Idempotency-Key", idempotencyKey)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"id": "file_y04rz07dh5k83ff2g4n1wtvgy7",
"object": "file",
"livemode": true,
"purpose": "output",
"status": "uploading",
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"size": 241587113,
"width": null,
"height": null,
"duration_ms": null,
"upload_url": "https://uploads.reflections.ai/file_y04rz07dh5k83ff2g4n1wtvgy7?expires=1792266127&signature=d33ef9140593995ffc3d0602234e8d46d86678cc63b",
"expires_at": "2026-10-18T18:42:07Z",
"created_at": "2026-10-17T18:42:07Z"
}Upload a file
Planned contract — unavailable in test and live modes. This operation is a protocol reference, not a callable endpoint. Start with the working sandbox quickstart.
Uploads a reference, voice sample or output. Send the bytes as multipart/form-data for
files up to 100 MB. For larger files, send JSON with the size and sha256 and upload the
bytes to the returned upload_url. A file is usable when its status is ready. Files
expire after 24 hours unless a held generation needs them longer.
Restricted keys need files:write.
# Set a unique key once per new action; persist it and reuse it for every retry.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
: "${REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/files' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15" \
-H "Idempotency-Key: $REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
--data-raw '{
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}'import { env, exit } from "node:process";
// Set a unique key once per new action; persist it and reuse it for every retry.
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const idempotencyKey = env.REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY;
if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/files", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
# Set a unique key once per new action; persist it and reuse it for every retry.
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
idempotencyKey = os.environ["REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY"]
if not idempotencyKey:
raise ValueError("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
}
data = json.dumps({
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4",
}).encode("utf-8")
request = Request("https://app.reflections.ai/v1/files",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
// Set a unique key once per new action; persist it and reuse it for every retry.
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
idempotencyKey := os.Getenv("REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY")
if idempotencyKey == "" {
panic("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")
}
body := strings.NewReader(`{
"purpose": "output",
"size": 241587113,
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"filename": "ridge-trail.mp4"
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/files", body)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
request.Header.Set("Idempotency-Key", idempotencyKey)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"id": "file_y04rz07dh5k83ff2g4n1wtvgy7",
"object": "file",
"livemode": true,
"purpose": "output",
"status": "uploading",
"sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
"media_type": "video/mp4",
"size": 241587113,
"width": null,
"height": null,
"duration_ms": null,
"upload_url": "https://uploads.reflections.ai/file_y04rz07dh5k83ff2g4n1wtvgy7?expires=1792266127&signature=d33ef9140593995ffc3d0602234e8d46d86678cc63b",
"expires_at": "2026-10-18T18:42:07Z",
"created_at": "2026-10-17T18:42:07Z"
}Authorizations
Your secret key, rk_test_… or rk_live_…, sent as Authorization: Bearer <key>. Keep it
on your server. Restricted keys carry only the scopes you give them.
Headers
The dated API version. Defaults to the version your account is pinned to.
"2026-10-15"
Act for a connected licensee. The value is the licensee's account ID. Requires an active connection between that account and yours.
^acct_[0-9a-hjkmnp-tv-z]{26}$A unique key for this operation, up to 255 characters. In test mode, POST keys are scoped to your account and mode and bind the endpoint and body for 24 hours. A different endpoint or body with the same key is refused.
Initial live check and generation creation require a nonempty key. Each operation has a
separate account-scoped namespace; retain the same API key, body and idempotency key for
retries within 24 hours of creation. A pending check returns 202 with status: "checking".
Completed checks replay their sealed response; successful generation POSTs replay the
original accepted 202, so use GET for current state. Live verification is a read-only
query that returns a fresh verification ID on each call, without exact response caching.
The broader delegated-account contract also scopes keys to Reflections-Account;
delegated requests and the other planned live POST operations remain unsupported.
255Body
Response
The file.
Unique identifier, prefixed file_. Send it as an input's file or an artifact's
file.
^file_[0-9a-hjkmnp-tv-z]{26}$Always file.
"file"true in live mode, false in test mode.
What the file is for: media a model receives, or an output to submit.
reference, voice_sample, mask, output uploading: waiting for the bytes at upload_url. ready: usable in checks and
generations. expired: deleted; upload it again.
uploading, ready, expired SHA-256 of the file's bytes, in hex.
^[0-9a-f]{64}$The file's MIME type.
Size in bytes.
When the file is deleted: 24 hours after it was created, or later while a held generation needs it.
When the file was created.
Width in pixels, for images and video. null for other files, and until the bytes
arrive.
Height in pixels, for images and video. null for other files, and until the bytes
arrive.
Length in milliseconds, for audio and video. null for other files, and until the bytes
arrive.
PUT the bytes here. Present while uploading; expires in 1 hour.