curl --request POST \
--url https://api.memories.ai/serve/api/v1/upload \
--header 'Authorization: <api-key>' \
--header 'Content-Type: multipart/form-data' \
--form file='@example-file' \
--form callback=https://your.app/callback \
--form 'datetime_taken=2025-10-20 11:00:00' \
--form 'camera_model=Canon EOS 5D' \
--form latitude=66.66 \
--form longitude=66.66 \
--form 'tags[0]=test1' \
--form 'tags[1]=test2' \
--form retain_original_video=true \
--form 'video_transcription_prompt=Focus on the speaker and major scene changes.' \
--form folder_id=671631448308117500import requests
url = "https://api.memories.ai/serve/api/v1/upload"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"callback": "https://your.app/callback",
"datetime_taken": "2025-10-20 11:00:00",
"camera_model": "Canon EOS 5D",
"latitude": "66.66",
"longitude": "66.66",
"tags[0]": "test1",
"tags[1]": "test2",
"retain_original_video": "true",
"video_transcription_prompt": "Focus on the speaker and major scene changes.",
"folder_id": "671631448308117500"
}
headers = {"Authorization": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('callback', 'https://your.app/callback');
form.append('datetime_taken', '2025-10-20 11:00:00');
form.append('camera_model', 'Canon EOS 5D');
form.append('latitude', '66.66');
form.append('longitude', '66.66');
form.append('tags[0]', 'test1');
form.append('tags[1]', 'test2');
form.append('retain_original_video', 'true');
form.append('video_transcription_prompt', 'Focus on the speaker and major scene changes.');
form.append('folder_id', '671631448308117500');
const options = {method: 'POST', headers: {Authorization: '<api-key>'}};
options.body = form;
fetch('https://api.memories.ai/serve/api/v1/upload', 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://api.memories.ai/serve/api/v1/upload",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: multipart/form-data"
],
]);
$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://api.memories.ai/serve/api/v1/upload"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.memories.ai/serve/api/v1/upload")
.header("Authorization", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.memories.ai/serve/api/v1/upload")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"code": "0000",
"msg": "success",
"data": {
"videoNo": "VI568102998803353600",
"videoName": "1be6a69f3c6e49bf986235d68807ab1f",
"videoStatus": "UNPARSE",
"uploadTime": "1744905509814"
},
"success": true,
"failed": false
}Upload Video — from File
Upload a local video file to your Private Video Library for indexing and search.
curl --request POST \
--url https://api.memories.ai/serve/api/v1/upload \
--header 'Authorization: <api-key>' \
--header 'Content-Type: multipart/form-data' \
--form file='@example-file' \
--form callback=https://your.app/callback \
--form 'datetime_taken=2025-10-20 11:00:00' \
--form 'camera_model=Canon EOS 5D' \
--form latitude=66.66 \
--form longitude=66.66 \
--form 'tags[0]=test1' \
--form 'tags[1]=test2' \
--form retain_original_video=true \
--form 'video_transcription_prompt=Focus on the speaker and major scene changes.' \
--form folder_id=671631448308117500import requests
url = "https://api.memories.ai/serve/api/v1/upload"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"callback": "https://your.app/callback",
"datetime_taken": "2025-10-20 11:00:00",
"camera_model": "Canon EOS 5D",
"latitude": "66.66",
"longitude": "66.66",
"tags[0]": "test1",
"tags[1]": "test2",
"retain_original_video": "true",
"video_transcription_prompt": "Focus on the speaker and major scene changes.",
"folder_id": "671631448308117500"
}
headers = {"Authorization": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('callback', 'https://your.app/callback');
form.append('datetime_taken', '2025-10-20 11:00:00');
form.append('camera_model', 'Canon EOS 5D');
form.append('latitude', '66.66');
form.append('longitude', '66.66');
form.append('tags[0]', 'test1');
form.append('tags[1]', 'test2');
form.append('retain_original_video', 'true');
form.append('video_transcription_prompt', 'Focus on the speaker and major scene changes.');
form.append('folder_id', '671631448308117500');
const options = {method: 'POST', headers: {Authorization: '<api-key>'}};
options.body = form;
fetch('https://api.memories.ai/serve/api/v1/upload', 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://api.memories.ai/serve/api/v1/upload",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: multipart/form-data"
],
]);
$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://api.memories.ai/serve/api/v1/upload"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.memories.ai/serve/api/v1/upload")
.header("Authorization", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.memories.ai/serve/api/v1/upload")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"callback\"\r\n\r\nhttps://your.app/callback\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"datetime_taken\"\r\n\r\n2025-10-20 11:00:00\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"camera_model\"\r\n\r\nCanon EOS 5D\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"latitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"longitude\"\r\n\r\n66.66\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B0%5D\"\r\n\r\ntest1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"tags%5B1%5D\"\r\n\r\ntest2\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"retain_original_video\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video_transcription_prompt\"\r\n\r\nFocus on the speaker and major scene changes.\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"folder_id\"\r\n\r\n671631448308117500\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"code": "0000",
"msg": "success",
"data": {
"videoNo": "VI568102998803353600",
"videoName": "1be6a69f3c6e49bf986235d68807ab1f",
"videoStatus": "UNPARSE",
"uploadTime": "1744905509814"
},
"success": true,
"failed": false
}https://api.memories.ai/serve/api/v1
Auth: Authorization: sk-mavi-... (no Bearer prefix)videoStatus: "UNPARSE"; register a callback URL or poll Get Metadata with the returned videoNo to know when indexing reaches PARSE.
Prerequisites
- You have created a memories.ai API key.
- Supported formats:
.mp4,.avi,.mkv,.mov.Content-Typeof the file part must start withvideo/. - Video codecs: h264, h265, vp9, hevc.
- Max file size: 3 GB.
Request Example
multipart/form-data. Send all non-file parameters as form fields, not JSON.import requests, os
headers = {"Authorization": "sk-mavi-..."}
file_path = "my_video.mp4"
with open(file_path, "rb") as f:
response = requests.post(
"https://api.memories.ai/serve/api/v1/upload",
headers=headers,
files={"file": (os.path.basename(file_path), f, "video/mp4")},
data={
"folder_id": 671631448308117504,
"callback": "https://your.app/callback",
"datetime_taken": "2025-10-20 11:00:00",
"camera_model": "Canon EOS 5D",
"latitude": "39.9042",
"longitude": "116.4074",
"tags": ["tag1", "tag2"],
"retain_original_video": True,
"video_transcription_prompt": "Focus on spoken dialogue"
}
)
print(response.json())
Parameters
.mp4, .avi, .mkv, or .mov and Content-Type must start with video/. Maximum 3 GB.-1) to store in your account’s Default folder (created automatically on first use). Pass a folder id from List Folders or Create Folder to store in that folder — it must belong to your account, otherwise the request is rejected.yyyy-MM-dd HH:mm:ss format (e.g. 2025-10-20 11:00:00). Invalid formats are rejected.["outdoor", "2025"]). Maximum 20 tags. An api tag is appended automatically.true.Response Example
{
"code": "0000",
"msg": "success",
"data": {
"videoNo": "VI568102998803353600",
"videoName": "1be6a69f3c6e49bf986235d68807ab1f",
"videoStatus": "UNPARSE",
"uploadTime": "1744905509814"
}
}
Response Fields
0000 indicates success.UNPARSE immediately after upload; transitions to PARSE once indexing completes.Knowing When Indexing Is Done
A successful upload returnsvideoStatus: "UNPARSE" — the video is queued for indexing but is not yet searchable. Two ways to wait for PARSE:
| Approach | How |
|---|---|
| Push (recommended for production) | Provide a callback URL on upload; memories.ai POSTs to it when indexing completes. |
| Poll | Call Get Metadata with video_no=<the videoNo above> and check data.status until it becomes PARSE. |
taskId. Single-file uploads return videoNo, not taskId.{
"videoNo": "VI554046065381212160",
"status": "PARSE"
}
Notes & Limits
- Rate limiting: Exceeding the per-account upload rate limit returns an error. See Rate limits.
- Concurrent indexing: There is a cap on how many videos can be in the indexing queue within a rolling 2-hour window. New uploads are rejected once the cap is reached until prior videos finish parsing.
- Billing: Each upload deducts credits from your account. Insufficient balance causes the request to fail.
Authorizations
Body
Video file to upload. Allowed extensions: .mp4, .avi, .mkv, .mov. Content-Type must start with video/. Max size 3 GB.
Callback URL invoked when the video moves to the parsing stage. Max 299 characters.
299"https://your.app/callback"
Capture time in format yyyy-MM-dd HH:mm:ss.
"2025-10-20 11:00:00"
Camera/device model. Max 200 characters.
200"Canon EOS 5D"
66.66
66.66
User-defined tags. Max 20. The server automatically appends an 'api' tag.
20["test1", "test2"]
"Focus on the speaker and major scene changes."
Optional target folder for the upload. Omit or pass -1 for the account's Default folder (auto-created on first use). A positive id must belong to your account.
671631448308117500
Response
Successful response
Business status code. 0000 indicates success.
"0000"
"success"
Show child attributes
Show child attributes
{ "videoNo": "VI568102998803353600", "videoName": "1be6a69f3c6e49bf986235d68807ab1f", "videoStatus": "UNPARSE", "uploadTime": "1744905509814" }
true
false
