> ## Documentation Index
> Fetch the complete documentation index at: https://api-tools.memories.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload Video — from File

> Upload a local video file to your Private Video Library for indexing and search.

<Info>
  **Product**: Visual Search
  **Use case**: Upload videos and images, auto-index them, then search by natural language, image, or transcript phrase
  **Host**: `https://api.memories.ai/serve/api/v1`
  **Auth**: `Authorization: sk-mavi-...` (no `Bearer` prefix)
</Info>

Upload a video file from disk into your **Private Video Library** for indexing and search. To pull a video from a remote URL instead, use [Upload Video — from URL](/visual-search/upload-video-from-url). For images, use [Upload Image](/visual-search/upload-image-from-file).

The upload queues the video for asynchronous indexing. The response returns immediately with `videoStatus: "UNPARSE"`; register a `callback` URL or poll [Get Metadata](/visual-search/get-metadata) with the returned `videoNo` to know when indexing reaches `PARSE`.

## Prerequisites

* You have [created a memories.ai API key](/visual-search/create-your-key).
* **Supported formats**: `.mp4`, `.avi`, `.mkv`, `.mov`. `Content-Type` of the file part must start with `video/`.
* **Video codecs**: h264, h265, vp9, hevc.
* **Max file size**: **3 GB**.

## Request Example

<Note>Uses `multipart/form-data`. Send all non-file parameters as form fields, not JSON.</Note>

```python theme={null}
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

<ParamField body="file" type="file" required>
  The video file. Extension must be `.mp4`, `.avi`, `.mkv`, or `.mov` and `Content-Type` must start with `video/`. Maximum **3 GB**.
</ParamField>

<ParamField body="folder_id" type="integer">
  Optional. Target folder for the uploaded video(s). Omit (or pass `-1`) to store in your account's **Default folder** (created automatically on first use). Pass a folder id from [List Folders](/visual-search/list-folders) or [Create Folder](/visual-search/create-folder) to store in that folder — it must belong to your account, otherwise the request is rejected.
</ParamField>

<ParamField body="callback" type="string">
  URL that receives a POST notification when the video finishes indexing. Maximum **299 characters**.
</ParamField>

<ParamField body="datetime_taken" type="string">
  Capture time in `yyyy-MM-dd HH:mm:ss` format (e.g. `2025-10-20 11:00:00`). Invalid formats are rejected.
</ParamField>

<ParamField body="camera_model" type="string">
  Camera or device model name. Maximum **200 characters**.
</ParamField>

<ParamField body="latitude" type="number">
  GPS latitude where the video was captured (decimal).
</ParamField>

<ParamField body="longitude" type="number">
  GPS longitude where the video was captured (decimal).
</ParamField>

<ParamField body="tags" type="array">
  User-defined tags (e.g. `["outdoor", "2025"]`). Maximum **20 tags**. An `api` tag is appended automatically.
</ParamField>

<ParamField body="retain_original_video" type="boolean" default="true">
  Whether to retain the original video file after indexing. Defaults to `true`.
</ParamField>

<ParamField body="video_transcription_prompt" type="string">
  Custom prompt to steer the transcription and video understanding focus.
</ParamField>

## Response Example

```json theme={null}
{
    "code": "0000",
    "msg": "success",
    "data": {
        "videoNo": "VI568102998803353600",
        "videoName": "1be6a69f3c6e49bf986235d68807ab1f",
        "videoStatus": "UNPARSE",
        "uploadTime": "1744905509814"
    }
}
```

## Response Fields

<ResponseField name="code" type="string">Business status code. `0000` indicates success.</ResponseField>
<ResponseField name="msg" type="string">Human-readable status message.</ResponseField>
<ResponseField name="data.videoNo" type="string">Unique identifier for the uploaded video. Use this in all subsequent operations.</ResponseField>
<ResponseField name="data.videoName" type="string">Internal name assigned to the stored video.</ResponseField>
<ResponseField name="data.videoStatus" type="string">Initial processing status. Always `UNPARSE` immediately after upload; transitions to `PARSE` once indexing completes.</ResponseField>
<ResponseField name="data.uploadTime" type="string">Upload timestamp in milliseconds since epoch.</ResponseField>

## Knowing When Indexing Is Done

A successful upload returns `videoStatus: "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](/visual-search/get-metadata) with `video_no=<the videoNo above>` and check `data.status` until it becomes `PARSE`. |

<Warning>
  Do **not** use [Get Task Status](/visual-search/get-task-status) here. That endpoint is for batch [Upload from Social Media](/visual-search/upload-from-post-urls) tasks, which return a `taskId`. Single-file uploads return `videoNo`, not `taskId`.
</Warning>

Callback payload, if you registered one:

```json theme={null}
{
    "videoNo": "VI554046065381212160",
    "status": "PARSE"
}
```

## Notes & Limits

* **Rate limiting**: Exceeding the per-account upload rate limit returns an error. See [Rate limits](/visual-search/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.


## OpenAPI

````yaml POST /serve/api/v1/upload
openapi: 3.1.0
info:
  title: Memories Platform API (Docs Mapping)
  version: v1
  description: OpenAPI mapping used by Mintlify Try it for the platform docs.
servers:
  - url: https://api.memories.ai
security:
  - ApiKeyAuth: []
paths:
  /serve/api/v1/upload:
    post:
      summary: Upload Video from File
      operationId: upload_video_from_file
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/UploadVideoRequest'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadVideoResponse'
components:
  schemas:
    UploadVideoRequest:
      type: object
      properties:
        file:
          type: string
          format: binary
          description: >-
            Video file to upload. Allowed extensions: .mp4, .avi, .mkv, .mov.
            Content-Type must start with video/. Max size 3 GB.
        callback:
          type: string
          format: uri
          maxLength: 299
          example: https://your.app/callback
          description: >-
            Callback URL invoked when the video moves to the parsing stage. Max
            299 characters.
        datetime_taken:
          type: string
          example: '2025-10-20 11:00:00'
          description: Capture time in format yyyy-MM-dd HH:mm:ss.
        camera_model:
          type: string
          maxLength: 200
          example: Canon EOS 5D
          description: Camera/device model. Max 200 characters.
        latitude:
          type: number
          format: double
          example: 66.66
        longitude:
          type: number
          format: double
          example: 66.66
        tags:
          type: array
          items:
            type: string
          maxItems: 20
          example:
            - test1
            - test2
          description: >-
            User-defined tags. Max 20. The server automatically appends an 'api'
            tag.
        retain_original_video:
          type: boolean
          default: true
        video_transcription_prompt:
          type: string
          example: Focus on the speaker and major scene changes.
        folder_id:
          type: integer
          description: >-
            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.
          example: 671631448308117500
      required:
        - file
    UploadVideoResponse:
      type: object
      properties:
        code:
          type: string
          example: '0000'
          description: Business status code. 0000 indicates success.
        msg:
          type: string
          example: success
        data:
          type: object
          properties:
            videoNo:
              type: string
              example: VI568102998803353600
              description: >-
                Unique identifier of the uploaded video. Use this for all
                subsequent operations.
            videoName:
              type: string
              example: 1be6a69f3c6e49bf986235d68807ab1f
              description: Internal stored name of the video.
            videoStatus:
              type: string
              example: UNPARSE
              description: >-
                Initial processing status. UNPARSE immediately after upload;
                transitions to parsing asynchronously.
            uploadTime:
              type: string
              example: '1744905509814'
              description: Upload timestamp in milliseconds since epoch (as string).
          example:
            videoNo: VI568102998803353600
            videoName: 1be6a69f3c6e49bf986235d68807ab1f
            videoStatus: UNPARSE
            uploadTime: '1744905509814'
        success:
          type: boolean
          example: true
        failed:
          type: boolean
          example: false
      example:
        code: '0000'
        msg: success
        data:
          videoNo: VI568102998803353600
          videoName: 1be6a69f3c6e49bf986235d68807ab1f
          videoStatus: UNPARSE
          uploadTime: '1744905509814'
        success: true
        failed: false
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization

````