> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reap.video/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Upload URL

> Get a presigned URL to upload video files to Reap

> **For AI agents:** a documentation index is at [/llms.txt](/llms.txt). Every page is also available as markdown, just append `.md` to the URL.

## Overview

Generate a secure, time-limited upload URL for video files. This endpoint creates a presigned URL that allows you to upload files directly to our storage service. After uploading, you can immediately use the upload ID in project creation - validation happens automatically when the file is first used.

## File Requirements

<CardGroup cols={2}>
  <Card title="Supported Formats" icon="file-video">
    **MP4** and **MOV** files only
  </Card>

  <Card title="File Size" icon="scale-balanced">
    **Maximum:** 5 GB per file
  </Card>

  <Card title="Filename Length" icon="ruler">
    **Maximum:** 1000 characters
  </Card>

  <Card title="Content Validation" icon="shield-check">
    Files are validated when first used in a project
  </Card>
</CardGroup>

## Response

<ResponseField name="uploadUrl" type="string">
  Presigned URL for uploading the file (expires after a limited time)
</ResponseField>

<ResponseField name="id" type="string">
  Unique identifier for this upload
</ResponseField>

<ResponseField name="fileName" type="string">
  Name of the file as it will be stored
</ResponseField>

<ResponseField name="fileType" type="string">
  Type of file ("video", "audio", or "image")
</ResponseField>

<ResponseField name="fileSize" type="integer" optional>
  Size of the file in bytes (null until upload completes)
</ResponseField>

<ResponseField name="contentType" type="string" optional>
  MIME type of the file (null until upload completes)
</ResponseField>

<ResponseField name="status" type="string">
  Current status of the upload ("upload", "verified", or "rejected")
</ResponseField>

<ResponseField name="createdAt" type="integer">
  Unix timestamp when the upload record was created
</ResponseField>

<ResponseField name="updatedAt" type="integer">
  Unix timestamp when the upload record was last updated
</ResponseField>

## Example Request

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST "https://public.reap.video/api/v1/automation/get-upload-url" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "filename": "my-presentation.mp4"
    }'
  ```

  ```javascript JavaScript theme={"system"}
  const response = await fetch('https://public.reap.video/api/v1/automation/get-upload-url', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      filename: 'my-presentation.mp4'
    })
  });

  const uploadData = await response.json();
  console.log('Upload URL:', uploadData.uploadUrl);
  console.log('Upload ID:', uploadData.id);
  ```

  ```python Python theme={"system"}
  import requests

  headers = {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
  }

  data = {
      'filename': 'my-presentation.mp4'
  }

  response = requests.post(
      'https://public.reap.video/api/v1/automation/get-upload-url',
      headers=headers,
      json=data
  )

  upload_data = response.json()
  print(f"Upload URL: {upload_data['uploadUrl']}")
  print(f"Upload ID: {upload_data['id']}")
  ```

  ```php PHP theme={"system"}
  <?php
  $url = 'https://public.reap.video/api/v1/automation/get-upload-url';
  $data = [
      'filename' => 'my-presentation.mp4'
  ];
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'Authorization: Bearer YOUR_API_KEY',
      'Content-Type: application/json'
  ]);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $response = curl_exec($ch);
  curl_close($ch);
  $upload_data = json_decode($response, true);
  echo 'Upload URL: ' . $upload_data['uploadUrl'] . "\n";
  echo 'Upload ID: ' . $upload_data['id'] . "\n";
  ```

  ```go Go theme={"system"}
  package main
  import (
      "bytes"
      "encoding/json"
      "fmt"
      "io/ioutil"
      "net/http"
  )
  func main() {
      url := "https://public.reap.video/api/v1/automation/get-upload-url"
      data := map[string]string{
          "filename": "my-presentation.mp4",
      }
      payload, _ := json.Marshal(data)
      req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
      req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
      req.Header.Set("Content-Type", "application/json")
      client := &http.Client{}
      resp, _ := client.Do(req)
      defer resp.Body.Close()
      body, _ := ioutil.ReadAll(resp.Body)
      fmt.Println(string(body))
  }
  ```

  ```java Java theme={"system"}
  import java.io.*;
  import java.net.HttpURLConnection;
  import java.net.URL;
  public class GetUploadUrlExample {
      public static void main(String[] args) throws Exception {
          URL url = new URL("https://public.reap.video/api/v1/automation/get-upload-url");
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          conn.setRequestMethod("POST");
          conn.setRequestProperty("Authorization", "Bearer YOUR_API_KEY");
          conn.setRequestProperty("Content-Type", "application/json");
          conn.setDoOutput(true);
          String jsonInputString = "{\"filename\": \"my-presentation.mp4\"}";
          try(OutputStream os = conn.getOutputStream()) {
              byte[] input = jsonInputString.getBytes("utf-8");
              os.write(input, 0, input.length);
          }
          BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
          StringBuilder response = new StringBuilder();
          String responseLine;
          while ((responseLine = br.readLine()) != null) {
              response.append(responseLine.trim());
          }
          System.out.println("Upload response: " + response.toString());
      }
  }
  ```
</CodeGroup>

## Example Response

<CodeGroup>
  <CodeGroup.Tab label="200 OK">
    ```json theme={"system"}
    {
      "uploadUrl": "https://reap-user-uploads.s3.amazonaws.com/studios/65f1a2b3c4d5e6f7a8b9c0d1/api-uploads/my-presentation-abc123.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...",
      "id": "65f1a2b3c4d5e6f7a8b9c0d1",
      "fileName": "my-presentation.mp4",
      "fileType": "video",
      "fileSize": null,
      "contentType": null,
      "status": "upload",
      "createdAt": 1710345600,
      "updatedAt": 1710345600
    }
    ```
  </CodeGroup.Tab>

  <CodeGroup.Tab label="400 Bad Request">
    ```json theme={"system"}
    {
      "detail": "Missing or invalid filename."
    }
    ```
  </CodeGroup.Tab>

  <CodeGroup.Tab label="400 Unsupported File Type">
    ```json theme={"system"}
    {
      "detail": "Unsupported file type. Supported file types: .mp4, .mov"
    }
    ```
  </CodeGroup.Tab>

  <CodeGroup.Tab label="401 Unauthorized">
    ```json theme={"system"}
    {
      "detail": "Unauthorized - Invalid or missing API key"
    }
    ```
  </CodeGroup.Tab>

  <CodeGroup.Tab label="429 Too Many Requests">
    ```json theme={"system"}
    {
      "detail": "Too Many Requests - Rate limit exceeded"
    }
    ```
  </CodeGroup.Tab>

  <CodeGroup.Tab label="500 Internal Server Error">
    ```json theme={"system"}
    {
      "detail": "Failed to create upload URL. Please try again."
    }
    ```
  </CodeGroup.Tab>
</CodeGroup>

## Upload Process

After receiving the upload URL, follow these steps:

### 1. Upload Your File

Use the provided `uploadUrl` to upload your video file:

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X PUT "UPLOAD_URL_FROM_RESPONSE" \
    -H "Content-Type: video/mp4" \
    --data-binary @/path/to/your/video.mp4
  ```

  ```python Python theme={"system"}
  import requests

  upload_url = "UPLOAD_URL_FROM_RESPONSE"
  file_path = "/path/to/your/video.mp4"

  with open(file_path, 'rb') as file:
      response = requests.put(
          upload_url,
          data=file,
          headers={'Content-Type': 'video/mp4'}
      )

  if response.status_code == 200:
      print("Upload successful!")
  else:
      print(f"Upload failed: {response.status_code}")
  ```
</CodeGroup>

<Warning>
  The upload URL expires after a limited time. Upload your file immediately after receiving the URL.
</Warning>

### 2. Use in Projects

After uploading, you can immediately use the upload ID in project creation endpoints like:

* [Create Clips](/api-reference/create-clips)
* [Create Captions](/api-reference/create-captions)
* [Create Transcription](/api-reference/create-transcription)
* [Create Reframe](/api-reference/create-reframe)
* [Create Dubbing](/api-reference/create-dubbing)

## File Validation

Files are validated when first used in a project. The validation process checks:

<CardGroup cols={2}>
  <Card title="File Format" icon="file-video">
    Must be MP4 or MOV format with valid video streams
  </Card>

  <Card title="File Size" icon="scale-balanced">
    Maximum size of 5 GB per file
  </Card>

  <Card title="Duration Limits" icon="clock">
    Varies by project type (see individual project endpoints)
  </Card>

  <Card title="Video Quality" icon="eye">
    Must contain valid video and audio streams
  </Card>
</CardGroup>

### Upload Status Flow

* **"upload"** - Initial status after file upload
* **"verified"** - File validated successfully when first used in a project
* **"rejected"** - File failed validation when first used in a project

<Note>
  Files remain in "upload" status until they are used in a project for the first time. Only then are they validated and marked as "verified" or "rejected".
</Note>

## Rate Limiting

This endpoint is subject to the standard rate limit of **10 requests per minute**.

## Best Practices

<Tip>
  * You can use upload IDs immediately after uploading - no need to wait for verification
  * Use descriptive filenames to help identify uploads later
  * Keep track of upload IDs for future reference
  * Handle upload failures gracefully by requesting new upload URLs
  * To reuse files, use uploads with "verified" status from the [Get All Uploads](/api-reference/get-all-uploads) endpoint
</Tip>

## Next Steps

After uploading your file:

1. Create a project using the upload ID (validation happens automatically):
   * [Create Clips](/api-reference/create-clips) - Generate short clips
   * [Create Captions](/api-reference/create-captions) - Add AI-generated captions
   * [Create Transcription](/api-reference/create-transcription) - Generate transcriptions
   * [Create Reframe](/api-reference/create-reframe) - Reframe for different aspect ratios
   * [Create Dubbing](/api-reference/create-dubbing) - Add voice dubbing
2. For reusing files, check [Get All Uploads](/api-reference/get-all-uploads) for uploads with "verified" status


## OpenAPI

````yaml POST /automation/get-upload-url
openapi: 3.1.0
info:
  title: Reap Automation API
  description: AI-powered video processing automation API
  version: 1.0.0
servers:
  - url: https://public.reap.video/api/v1
security:
  - bearerAuth: []
paths:
  /automation/get-upload-url:
    post:
      summary: Get Upload URL
      description: Get a presigned URL to upload video files
      operationId: getUploadUrl
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - filename
              properties:
                filename:
                  type: string
                  description: >-
                    Name of the file to upload (must include .mp4 or .mov
                    extension)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadUrlResponse'
components:
  schemas:
    UploadUrlResponse:
      type: object
      properties:
        uploadUrl:
          type: string
        id:
          type: string
        fileName:
          type: string
        fileType:
          type: string
          enum:
            - video
            - audio
            - image
        fileSize:
          type: integer
          nullable: true
        contentType:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - upload
            - verified
            - rejected
        createdAt:
          type: integer
        updatedAt:
          type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````