curl --request POST \
--url https://api.apimart.ai/v1/uploads/videos \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.mp4'
import requests
with open("reference.mp4", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/videos",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/videos", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.mp4",
"filename": "reference.mp4",
"content_type": "video/mp4",
"file_type": "video",
"bytes": 235680,
"created_at": 1793836800,
"quota": {
"limit": 2000,
"used": 124,
"remaining": 1876,
"window_hours": 72,
"reset_at": 1794063600
}
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "video file exceeds maximum 52428800 bytes (50MB)",
"type": "invalid_request_error"
}
}
{
"error": {
"message": "upload limit reached: each account can upload at most 2000 files per 72 hours",
"type": "rate_limit_exceeded",
"code": "rate_limit_exceeded",
"param": ""
},
"quota": {
"limit": 2000,
"used": 2000,
"remaining": 0,
"window_hours": 72,
"reset_at": 1794063600
}
}
Upload Management
Upload Video
Upload an MP4, MOV, or WebM video to get a public URL for generation APIs. Default file limit: 50MB.
POST
/
v1
/
uploads
/
videos
curl --request POST \
--url https://api.apimart.ai/v1/uploads/videos \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.mp4'
import requests
with open("reference.mp4", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/videos",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/videos", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.mp4",
"filename": "reference.mp4",
"content_type": "video/mp4",
"file_type": "video",
"bytes": 235680,
"created_at": 1793836800,
"quota": {
"limit": 2000,
"used": 124,
"remaining": 1876,
"window_hours": 72,
"reset_at": 1794063600
}
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "video file exceeds maximum 52428800 bytes (50MB)",
"type": "invalid_request_error"
}
}
{
"error": {
"message": "upload limit reached: each account can upload at most 2000 files per 72 hours",
"type": "rate_limit_exceeded",
"code": "rate_limit_exceeded",
"param": ""
},
"quota": {
"limit": 2000,
"used": 2000,
"remaining": 0,
"window_hours": 72,
"reset_at": 1794063600
}
}
Upload reference media and receive a public URL immediately on success; no polling is needed. Uploading is free, but your account balance must be positive. The three upload endpoints share a per-user quota, defaulting to 2000 files over 72 hours.
The documentation Playground does not support file uploads. Use the cURL, Python, or JavaScript examples below. The JavaScript example requires an
<input type="file"> with a file selected on the page.curl --request POST \
--url https://api.apimart.ai/v1/uploads/videos \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.mp4'
import requests
with open("reference.mp4", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/videos",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/videos", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.mp4",
"filename": "reference.mp4",
"content_type": "video/mp4",
"file_type": "video",
"bytes": 235680,
"created_at": 1793836800,
"quota": {
"limit": 2000,
"used": 124,
"remaining": 1876,
"window_hours": 72,
"reset_at": 1794063600
}
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "video file exceeds maximum 52428800 bytes (50MB)",
"type": "invalid_request_error"
}
}
{
"error": {
"message": "upload limit reached: each account can upload at most 2000 files per 72 hours",
"type": "rate_limit_exceeded",
"code": "rate_limit_exceeded",
"param": ""
},
"quota": {
"limit": 2000,
"used": 2000,
"remaining": 0,
"window_hours": 72,
"reset_at": 1794063600
}
}
Authentication
string
required
Use a valid, enabled, unexpired APIMart API Key as
Bearer <token>, with an account that is not suspended. The account balance must be positive; exhausting the Key’s own quota does not prevent uploads. Get a Key from API Key management.Request parameters
file
required
Send one file, including its filename, in the
file field of a multipart/form-data request. Do not substitute JSON, a base64 string, or a file URL for the file part. Other form fields are ignored; if multiple file parts are sent, only the first is processed.Supported formats: MP4 (.mp4), MOV (.mov), WebM (.webm)Default maximum file size: 50MB. File size limits can be configured. The active service configuration and size-limit error message take precedence.--form, Python files, or JavaScript FormData, let the client generate the Content-Type header with its boundary. Do not set this header manually.
File validation
The file type is detected from its content, not its extension or the MIME type supplied by the client. The content must match the endpoint; renaming a file does not convert it. A type mismatch returns HTTP400.
Video container structure is validated. Fake file headers or damaged containers are rejected. Only the formats below are supported; renaming AVI, MKV, or other formats does not make them valid.
| Format | Detected MIME type |
|---|---|
| MP4 (.mp4) | video/mp4 |
| MOV (.mov) | video/quicktime |
| WebM (.webm) | video/webm |
Successful response
HTTP200 returns file metadata. url is at the JSON root, without a data wrapper or a generation task ID.
string
Public file URL. Pass it to the appropriate reference-media parameter of the target generation API. Each model still has its own format, size, count, and duration limits; a successful upload does not guarantee model compatibility.
string
Original filename.
string
MIME type detected by the server from the file content, not the client’s declared value.
string
File category. This endpoint returns
video.integer
Actual file size in bytes.
integer
Upload time as a Unix timestamp in seconds.
object
Optional upload quota information. Fields for a quota-limited user are listed below; unlimited access or temporarily unavailable statistics may produce a different structure, as explained below.
| Field | Description |
|---|---|
quota.limit | Maximum successful uploads for this user within the window; it may differ from the default of 2000. |
quota.used | Used slots within the window, including this successful upload. |
quota.remaining | Number of files that can currently still be uploaded. |
quota.window_hours | Window length in hours; defaults to 72. |
quota.reset_at | Time when the oldest batch leaves the window, in Unix seconds. Some slots become available then; the entire quota does not necessarily reset at once. |
Shared quota and request rate limits
Image, video, and audio uploads share one per-user quota. Multiple API Keys for the same user do not add quota. The window rolls on the hour and, by default, counts successful uploads over approximately the past 71–72 hours. Invalid files, oversized files, and storage failures do not consume file quota. Normal quota-limited responses also includeX-Upload-Quota-Limit, X-Upload-Quota-Remaining, and X-Upload-Quota-Reset, corresponding to limit, remaining, and reset_at. Reset is in Unix seconds.
Unlimited users receive quota: {"unlimited": true} without those three quota headers. When statistics are temporarily unavailable, a successful response may omit quota. Do not interpret missing statistics as zero or unlimited, or re-upload solely because quota information is absent.
Exhausted file quota returns HTTP 429 with error.type: rate_limit_exceeded, quota (remaining: 0), and Retry-After. Wait the specified number of seconds before retrying. A separate limit of 1000 requests per Key per 60 seconds uses rate_limit_error; it is independent of the file quota.
Error handling
Errors use a root-levelerror object. Inspect the HTTP status, error.type / error.code, and error.message to determine the cause.
| HTTP | error.type | Cause and action |
|---|---|---|
| 400 | invalid_request_error | Missing file, non-multipart request, empty file, wrong media type, unsupported format, or damaged content. Fix the file or endpoint before retrying. |
| 401 / 403 | — | Invalid or disabled Key, or suspended account. Check authentication and account status. |
| 402 | insufficient_user_quota | Non-positive account balance or expired Key. Add balance or use a valid Key. Free uploads still require these access conditions. |
| 413 | invalid_request_error | The file exceeds the limit for its type. Compress or reduce it; use the current limit stated in the error message. |
| 429 | rate_limit_exceeded | The user’s shared file quota is exhausted. Read quota and Retry-After, then wait for slots to become available. |
| 429 | rate_limit_error | Too many requests from the Key. Reduce request frequency and retry with backoff. |
| 503 | server_error | Too many concurrent video/audio uploads, or temporarily unavailable storage. Retry later. |
| 500 | server_error | Failed to write the file to storage. Retry later. |