> ## 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 URL

> Upload a video by direct URL — the server fetches the file at request time and queues it for indexing.

<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>

Pull a video from a publicly reachable URL (mp4 or m3u8) into your **Private Video Library** for indexing and search. For uploading a local file, use [Upload Video — from File](/visual-search/upload-video-from-file). To import from a social platform (TikTok / YouTube / Instagram), use [Upload from Social Media](/visual-search/upload-from-post-urls).

## Prerequisites

* You have [created a memories.ai API key](/visual-search/create-your-key).
* The video URL is **publicly accessible via unauthenticated HTTP GET** — the server fetches it at request time, so temporary or expiring links may fail.
* **Video codecs**: h264, h265, vp9, hevc. m3u8 streams are supported only if all internal paths are fully absolute.
* **Max file size**: 1 GB; files larger than 1 GB require special account permission — contact support.

## Request Example

<Note>Uses `application/x-www-form-urlencoded`. Send parameters as form fields, not JSON.</Note>

```python theme={null}
import requests

headers = {"Authorization": "sk-mavi-..."}
response = requests.post(
    "https://api.memories.ai/serve/api/v1/upload_url",
    headers=headers,
    data={
        "url": "https://example.com/video.mp4",
        "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="url" type="string" required>
  Direct URL to the video. Must be publicly accessible via unauthenticated HTTP GET. The server fetches from this URL at request time — ensure it remains available until download starts.
</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. 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. 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.
</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

The response returns immediately with `videoStatus: "UNPARSE"` — the video is queued for indexing but **is not yet searchable**. Two ways to wait for `PARSE`:

| Approach | How                                                                                                                                    |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Push** | 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) — that endpoint is only for batch [Upload from Social Media](/visual-search/upload-from-post-urls) tasks (which return a `taskId`, not a `videoNo`).
</Warning>

## Notes & Limits

* **Source availability**: The URL must remain accessible until the server fetches the video. Temporary or expiring links may fail.
* **Rate limiting**: Exceeding the per-account upload rate limit returns an error.
* **Concurrent indexing cap**: New uploads are rejected once the rolling 2-hour cap is reached.
* **Billing**: Each upload deducts credits from your account balance.


## OpenAPI

````yaml POST /serve/api/v1/upload_url
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_url:
    post:
      summary: Upload Video from URL
      operationId: upload_video_from_url
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/UploadVideoFromUrlRequest'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadVideoResponse'
components:
  schemas:
    UploadVideoFromUrlRequest:
      type: object
      properties:
        url:
          type: string
          format: uri
          example: https://example.com/test_video.mp4
          description: >-
            Direct URL of the video. Must be reachable via unauthenticated HTTP
            GET.
        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
          description: Whether to retain the original source video. Defaults to 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:
        - url
    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

````