Files API
Upload image, video, or audio reference files for Rivya API generation requests, with MIME checks, size limits, and duration tokens.
Last reviewed on August 26, 2026
Use POST /api/v1/files to upload reference media for models that need image, video, or audio inputs.
Files API is for reference inputs only. It does not create generation tasks by itself. After upload, pass the returned url and metadata into model params, usually through params.referenceMediaItems.
Endpoint
POST https://rivya.ai/api/v1/files
GET https://rivya.ai/api/v1/files/{fileId}Required headers:
Authorization: Bearer rvya_sk_...
Content-Type: multipart/form-dataThe API key must include the files:create scope to upload and files:read to retrieve metadata. Newly created Rivya API keys include both scopes by default.
Multipart Fields
| Field | Type | Required | Notes |
|---|---|---|---|
file | binary | yes | The image, video, or audio file to upload. |
kind | string | yes | One of image, video, or audio. |
model | string | no | Public model ID. When present, Rivya validates that the model accepts this file kind. |
client_request_id | string | no | Your trace ID, up to 128 characters. |
Use model when the file is intended for a specific model. This gives you model-specific MIME and size validation before the file is accepted.
Upload Limits
Files API uses the same upload policy as Rivya reference uploads.
Default limits:
| Kind | Default max size | Common MIME types |
|---|---|---|
image | 10 MB | image/jpeg, image/png, image/webp |
video | 50 MB | video/mp4, video/quicktime, video/webm |
audio | 10 MB | audio/mpeg, audio/mp4, audio/wav, audio/x-wav, audio/aac, audio/ogg |
Some models have different limits. For example, selected reference-image models allow larger images, and selected video-reference models allow files up to the product's edge-safe upload ceiling. Always pass model when you know the target model, and read Model API Reference before accepting user uploads.
Signed image-reference limits include:
| Model | Maximum images | Per-image limit | Accepted image MIME types |
|---|---|---|---|
seedream-5-pro | 10 | 10 MB | JPEG, PNG, WebP |
seedream-5-pro-layer-decomposition | exactly 1 | 30 MB | JPEG, PNG, WebP, BMP, GIF, TIFF |
nano-banana-2-lite | 10 | 30 MB | JPEG, PNG, WebP |
qwen-image-3 / qwen-image-3-pro | 3 | 10 MB | JPEG, PNG, WebP, BMP, GIF, TIFF |
grok-imagine-image-2-0 | 5 | 10 MB | JPEG, PNG, WebP |
wan-3-0-video | 10 in reference mode; 1–2 in frames mode | 20 MB | JPEG, non-transparent PNG, WebP, BMP |
Every Image5, Grok Imagine Image 2.0, or Wan 3.0 reference image must be uploaded with its target model. Keep the original response's width, height, size_bytes, and image_dimensions_token; the generation request must send them as width, height, sizeBytes, and imageDimensionsToken. Arbitrary external image URLs do not satisfy this model-bound validation.
Layer decomposition additionally validates the detected image dimensions before upload: 262,144–36,000,000 pixels total and an aspect ratio from 1:16 through 16:1.
Video-reference model-specific upload limits include:
| Model | Image inputs | Video inputs | Audio inputs |
|---|---|---|---|
kling-3-turbo | 1 × 10 MB; JPEG or PNG | not accepted | not accepted |
seedance-2-mini | up to 9 × 30 MB; JPEG, PNG, WebP, BMP, GIF, or TIFF | up to 3 × 50 MB; MP4 or MOV | up to 3 × 15 MB; MP3 or WAV |
seedance-2-5 | up to 30 × 30 MB; JPEG, PNG, WebP, BMP, GIF, or TIFF | up to 10 × 95 MB; MP4 or MOV | up to 10 × 15 MB; MP3 or WAV |
minimax-h3 | up to 9 × 30 MB; JPEG, PNG, or WebP | up to 3 × 50 MB; MP4 or MOV | up to 3 × 15 MB; MP3 or WAV |
happyhorse-1-1 | up to 9 × 20 MB; JPEG, PNG, or WebP | not accepted | not accepted |
omnihuman-1-5 | 1 × 10 MB; JPEG, PNG, or WebP | not accepted | 1 × 10 MB; MP3, M4A, WAV, AAC, or OGG |
volcengine-video-lip-sync | not accepted | 1 × 95 MB; MP4 or MOV | 1 × 10 MB; MP3, M4A, WAV, AAC, or OGG |
wan-3-0-video | frames: 1 required and 1 optional; reference: up to 10 × 20 MB; JPEG, non-transparent PNG, WebP, or BMP | reference: up to 5 × 95 MB; MP4 or MOV; 1–15 seconds each and 15 seconds total | reference: up to 5 × 15 MB; MP3 or WAV; 1–15 seconds each and 15 seconds total; not accepted alone |
These are Rivya's accepted upload ceilings, which may be lower than an upstream service limit. Upload each Video8 or Wan 3.0 reference with its target model. Reference videos require both the signed duration proof and the signed video metadata from the original model-bound upload response. Wan 3.0 audio duration tokens also bind the detected MIME type and upload byte size.
Wan 3.0 images must be 240–8,000 pixels per side, and videos must be 240–4,096 pixels per side; both stay within a 1:8–8:1 aspect-ratio boundary. In reference mode, video and audio have separate 15-second aggregate limits, and audio cannot be the only reference kind.
Rivya validates the detected file signature, not only the filename extension.
curl Example
curl https://rivya.ai/api/v1/files \
-H "Authorization: Bearer rvya_sk_..." \
-F "file=@./reference.png" \
-F "kind=image" \
-F "model=nano-banana-2-lite" \
-F "client_request_id=asset-123"JavaScript Example
import { readFile } from "node:fs/promises";
const form = new FormData();
const file = new Blob([await readFile("./reference.png")], {
type: "image/png"
});
form.set("file", file, "reference.png");
form.set("kind", "image");
form.set("model", "nano-banana-2-lite");
form.set("client_request_id", "asset-123");
const response = await fetch("https://rivya.ai/api/v1/files", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIVYA_API_KEY}`
},
body: form
});
const uploadedFile = await response.json();
console.log(uploadedFile.id, uploadedFile.url);Python Example
import os
import requests
with open("./reference.png", "rb") as file_handle:
response = requests.post(
"https://rivya.ai/api/v1/files",
headers={
"Authorization": f"Bearer {os.environ['RIVYA_API_KEY']}",
},
files={"file": ("reference.png", file_handle, "image/png")},
data={
"kind": "image",
"model": "nano-banana-2-lite",
"client_request_id": "asset-123",
},
timeout=60,
)
uploaded_file = response.json()
print(uploaded_file["id"], uploaded_file["url"])Response
{
"id": "file_...",
"object": "file",
"kind": "image",
"file_name": "reference.png",
"mime_type": "image/png",
"size_bytes": 482314,
"url": "https://...",
"duration_seconds": null,
"duration_token": null,
"width": 1024,
"height": 1024,
"image_dimensions_token": "signed_image_metadata_token",
"video_width": null,
"video_height": null,
"frames_per_second": null,
"video_bitrate_mbps": null,
"video_file_size_bytes": null,
"video_metadata_token": null,
"created_at": "2026-05-11T00:00:00.000Z",
"expires_at": null
}For video and audio uploads, duration_seconds may be populated. When a model requires duration verification, copy duration_token into the related generation parameter as durationToken.
For supported image uploads, width and height are detected from the file bytes. All five Image5 models, Grok Imagine Image 2.0, and Wan 3.0 require the signed image_dimensions_token from the original model-bound upload response; copy it into the reference item as imageDimensionsToken, and copy size_bytes as sizeBytes. A later file-metadata retrieval may return that token as null, so re-upload the source image if the original token is unavailable or expired.
For supported Video8 and Wan 3.0 video uploads, Rivya inspects the MP4 or MOV bytes and returns video_width, video_height, frames_per_second, video_bitrate_mbps, video_file_size_bytes, and video_metadata_token. Copy them into the reference item as width, height, framesPerSecond, videoBitrateMbps, sizeBytes, and videoMetadataToken. The token is bound to the account, target model, URL, MIME type, dimensions, frame rate, bitrate, and upload size. Duration is verified separately with durationToken. A later file-metadata retrieval may return video_metadata_token as null; re-upload the source video instead of inventing metadata.
Retrieve File Metadata
Use GET /api/v1/files/{fileId} to read metadata for a file owned by the same Rivya account:
curl https://rivya.ai/api/v1/files/file_... \
-H "Authorization: Bearer rvya_sk_..."The response uses the same PublicApiFile shape as upload. If the file belongs to another account or is no longer available, the API returns not_found.
Use The Upload In Generation Params
Do not send a top-level files field to POST /api/v1/generations.
For new integrations, pass the upload result through params.referenceMediaItems:
{
"model": "nano-banana-2-lite",
"prompt": "Restyle this product photo for a clean editorial catalog page",
"params": {
"referenceMediaItems": [
{
"url": "https://...",
"kind": "image",
"name": "reference.png",
"mimeType": "image/png",
"width": 1024,
"height": 1024,
"sizeBytes": 482314,
"imageDimensionsToken": "image_dimensions_token_from_files_api"
}
]
},
"client_request_id": "order-123-preview"
}For video or audio:
{
"url": "https://...",
"kind": "video",
"name": "source.mov",
"mimeType": "video/quicktime",
"durationSeconds": 12.4,
"durationToken": "duration_token_from_files_api",
"width": 1920,
"height": 1080,
"framesPerSecond": 30,
"videoBitrateMbps": 8.5,
"sizeBytes": 26214400,
"videoMetadataToken": "video_metadata_token_from_files_api"
}The complete signed video fields above are required for Video8 and Wan 3.0 video references. Wan 3.0 audio references use mimeType, sizeBytes, durationSeconds, and durationToken; image references use the model-specific image metadata contract described above.
For Seedream 5.0 Pro Layer Decomposition, send exactly one image and the signed metadata returned by its model-bound upload:
{
"model": "seedream-5-pro-layer-decomposition",
"prompt": "Separate the product, shadow, typography, and background into clean layers",
"params": {
"size": "auto",
"output_format": "png",
"referenceMediaItems": [
{
"url": "https://...",
"kind": "image",
"name": "campaign.tiff",
"mimeType": "image/tiff",
"width": 2048,
"height": 2048,
"sizeBytes": 6291456,
"imageDimensionsToken": "image_dimensions_token_from_files_api"
}
]
}
}Some older model parameters still use model-specific URL fields. If the Model API Reference documents a specific parameter, follow that model page instead of inventing a new field.
Errors
Files API uses the same public error envelope as the rest of Rivya API:
{
"error": {
"code": "validation_failed",
"message": "The request is invalid.",
"requestId": "req_..."
}
}Common cases:
| HTTP | Code | Cause |
|---|---|---|
| 400 | validation_failed | Missing file, unsupported kind, unsupported MIME type, file too large, or model does not accept the selected kind. |
| 401 | api_key_missing / api_key_invalid | Missing or invalid Bearer API key. |
| 403 | api_scope_denied | The key does not include files:create or files:read for the requested action. |
| 429 | rate_limited | Too many file uploads in the current minute. |
| 503 | public_api_disabled | Public API is disabled in the current environment. |
Security Notes
Do not store full API keys in browsers, mobile clients, logs, analytics events, or screenshots.
Treat uploaded file URLs, duration_token, image_dimensions_token, and video_metadata_token values as temporary integration material. Use them only to build the follow-up generation request, and do not expose them in public pages.
