> This page is for 플랫폼, version V4 실험적.
> For other versions, use one of these documentation indexes:
> - V4 (default): https://next.developer.frame.io/platform/v4/llms.txt
> - V4 실험적: https://next.developer.frame.io/platform/v4-experimental/llms.txt
> - 레거시: https://next.developer.frame.io/platform/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# 로컬 및 원격 업로드 작동 방식

이 가이드에서는 Frame.io V4 API를 사용하여 파일을 업로드하는 전체 과정을 자세히 설명합니다. 로컬 및 원격 업로드 모두에 대한 원시 API 요청과 응답을 다룹니다.

> **Info**
>
> **SDK 전용 가이드가 필요하신가요?** 청킹, 재시도, 진행률 추적 기능이 내장된 업로드 연동에 대해서는 [Python SDK 업로드 가이드](./python-sdk-upload-guide)를 참조하세요.

## 사전 요구 사항

파일 업로드를 시작하기 전에 다음 설정 단계를 완료했는지 확인하세요.

#### Frame.io V4 계정

[Adobe Admin Console](https://adminconsole.adobe.com/)을 통해 관리되는 Frame.io V4 계정이 있거나, 계정 사용자를 위해 [Adobe 인증으로 전환](https://help.frame.io/ko/articles/11758018-connecting-to-adobe-authentication)했습니다.

#### Adobe Developer Console 설정

[Adobe Developer Console](https://developer.adobe.com/console)에 로그인하여 신규 또는 기존 프로젝트에 Frame.io API를 추가했습니다.

#### 인증 자격 증명

프로젝트에 [적합한 인증 자격 증명](https://developer.adobe.com/frameio/guides/Authentication/)을 생성했습니다.

#### 액세스 토큰

해당 자격 증명을 사용하여 액세스 토큰을 성공적으로 생성했습니다.

## 업로드 방법 선택

Frame.io API를 사용하여 파일을 업로드하는 방법에는 `파일 생성(로컬 업로드)`과 `파일 생성(원격 업로드)` 두 가지가 있습니다.

#### 로컬 업로드

바탕 화면에서 파일을 드래그하는 것과 같이 애플리케이션에서 미디어에 로컬로 액세스할 수 있는 경우에 사용합니다.

#### 원격 업로드

다른 서비스와의 연동 등 네트워크를 통해 미디어에 액세스할 때 사용합니다.

이 가이드에서는 원격 업로드를 완료하는 더 간단한 사례부터 살펴보겠습니다.

## 원격 업로드

원격 업로드를 통해 파일을 생성하려면 **파일 생성(원격 업로드)** 엔드포인트를 선택합니다. 요청 본문에는 파일 이름과 소스 URL이 필요합니다.

> **Warning**
>
> 현재 원격 업로드의 **파일 크기 제한은 50GB**입니다. 50GB보다 큰 파일의 경우 [로컬 업로드](#local-upload)를 사용하세요.

### 요청 예시

```json
{ 
    "data": {
        "name": "my_file.jpg",
        "source_url": "https://upload.wikimedia.org/wikipedia/commons/e/e1/White_Pixel_1x1.jpg"
    }
}
```

### 응답 예시

요청에 성공하면 다음과 같은 응답이 생성됩니다.

```json
{
    "data": {
        "id": "93e4079d-0a8a-4bf3-96cd-e6a03c465e5e",
        "name": "my_file.jpg",
        "status": "created",
        "type": "file",
        "file_size": 518,
        "updated_at": "2025-06-26T20:14:33.796116Z",
        "media_type": "image/jpeg",
        "parent_id": "2e426fe0-f965-4594-8b2b-b4dff1dc00ec",
        "project_id": "7e46e495-4444-4555-8649-bee4d391a997",
        "created_at": "2025-06-26T20:14:33.159489Z",
        "view_url": "https://next.frame.io/project/7e46e495-4444-4555-8649-bee4d391a997/view/93e4079d-0a8a-4bf3-96cd-e6a03c465e5e"
    },
    "links": {
        "status": "/v4/accounts/6f70f1bd-7e89-4a7e-b4d3-7e576585a181/files/93e4079d-0a8a-4bf3-96cd-e6a03c465e5e/status"
    }
}
```

## 로컬 업로드

로컬 업로드를 통해 파일을 생성하려면 **파일 생성(로컬 업로드)** 엔드포인트를 선택합니다. 요청 본문에는 파일 이름과 바이트 단위로 지정된 파일 크기가 필요합니다.

### 요청 예시

```json
{ 
    "data": {
        "name": "my_file.jpg",
        "file_size": 50645990
    }
}
```

### 응답 예시

요청에 성공하면 콘텐츠가 없는 자리 표시자 파일 리소스가 생성됩니다. 파일 크기에 따라 응답 본문에는 하나 이상의 `upload_urls`가 포함됩니다. 이 예시의 경우 해당 업로드를 여러 부분으로 나누어 관리해야 합니다.

```json
{
    "data": {
        "id": "fa18ba7b-b3ee-4dd6-9b31-bd07e554241d",
        "name": "my_file.jpg",
        "status": "created",
        "type": "file",
        "file_size": 50645990,
        "updated_at": "2025-06-26T20:08:06.823170Z",
        "media_type": "image/jpeg",
        "parent_id": "2e426fe0-f965-4594-8b2b-b4dff1dc00ec",
        "project_id": "7e46e495-4444-4555-8649-bee4d391a997",
        "created_at": "2025-06-26T20:08:06.751313Z",
        "upload_urls": [
            {
                "size": 16881997,
                "url": "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_1?..."
            },
            {
                "size": 16881997,
                "url": "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_2?..."
            },
            {
                "size": 16881996,
                "url": "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_3?..."
            }
        ],
        "view_url": "https://next.frame.io/project/7e46e495-4444-4555-8649-bee4d391a997/view/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d"
    }
}
```

> **Warning**
>
> **중요 업로드 요구 사항.**
>
> 후속 업로드 요청을 보낼 때 다음의 중요한 세부 사항을 유의해야 합니다.
>
> * HTTP 요청 메서드는 `PUT`이어야 합니다.
> * `x-amz-acl` 헤더가 포함되어야 하며 private으로 설정해야 합니다.
> * `Content-Type` 헤더는 원래의 **파일 생성(로컬 업로드)** 요청에 지정된 `media_type`과 일치해야 합니다. 이는 파일을 여러 부분으로 나누어 업로드할 때도 마찬가지입니다. 위 예시에서 `media_type`의 값은 `image/jpeg`입니다. 따라서 `Content-Type`의 값도 `image/jpeg`여야 합니다.

## 멀티파트 업로드

지정된 파일이 둘 이상의 업로드 URL을 반환하는 경우 소스 파일을 청크로 분할하고 각 청크에 대해 PUT 요청을 실행해야 합니다.

> **Info**
>
> **권장 사항:**[Python SDK 업로드 가이드](./python-sdk-upload-guide)에서는 청킹, 병렬 업로드, 재시도, 진행률 추적을 기본으로 처리하는 `FrameioUploader`를 사용한 멀티파트 업로드 방법을 다룹니다.

SDK가 없는 언어나 프로세스를 완전히 제어하기 위해 업로드를 수동으로 구현해야 하는 경우 아래 스크립트는 파일을 청크로 분할하고 사전 서명된 URL을 사용하여 각 청크를 업로드하는 방법을 보여 줍니다.

### Python 구현 예제

**`멀티파트 업로드 스크립트`**

```python title="멀티파트 업로드 스크립트"
import requests
import math
from typing import List
from tqdm import tqdm  # For progress bar

def upload_file_in_chunks(file_path: str, upload_urls: list[str], content_type: str | None = None, chunk_size: int | None = None) -> bool:
    """
    Upload a file in chunks using presigned URLs.
    """
    try:
        # Auto-detect content type based on file extension
        if content_type is None:
            detected_content_type, _ = mimetypes.guess_type(file_path)
            content_type = detected_content_type # Default fallback

        print(f"Detected content type: {content_type}")

        # Get file size
        with open(file_path, 'rb') as f:
            f.seek(0, 2)  # Seek to end of file
            file_size = f.tell()

        # Calculate chunk size if not provided
        if chunk_size is None:
            chunk_size = math.ceil(file_size / len(upload_urls))

        print(f"File size: {file_size} bytes")
        print(f"Chunk size: {chunk_size} bytes")
        print(f"Number of chunks: {len(upload_urls)}")

        # Upload each chunk
        with open(file_path, 'rb') as f:
            with tqdm(total=len(upload_urls), desc="Uploading chunks") as pbar:
                for i, url in enumerate(upload_urls):
                    start_byte = i * chunk_size
                    end_byte = min(start_byte + chunk_size, file_size)

                    # Read chunk from file
                    f.seek(start_byte)
                    chunk = f.read(end_byte - start_byte)

                    print(f"Uploading chunk {i+1}: {len(chunk)} bytes")

                    # Upload chunk with minimal headers matching the signature
                    response = requests.put(
                        url,
                        data=chunk,
                        headers={
                            'content-type': content_type,
                            'x-amz-acl': 'private'
                        }
                    )

                    if response.status_code != 200:
                        print(f"Failed to upload chunk {i+1}. Status code: {response.status_code}")
                        print(f"Response text: {response.text}")
                        print(f"Response headers: {dict(response.headers)}")
                        return False
                    else:
                        print(f"Chunk {i+1} uploaded successfully!")

                    pbar.update(1)

        return True

    except Exception as e:
        print(f"Error during upload: {str(e)}")
        return False

# Example usage
if __name__ == "__main__":
    # Replace these with your actual values
    file_path = "/Users/MyComputer/local_upload/sample.jpg"  # Path to your file
    upload_urls = [
        "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_1?...",
        "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_2?...",
        "https://frameio-uploads-development.s3-accelerate.amazonaws.com/parts/fa18ba7b-b3ee-4dd6-9b31-bd07e554241d/part_3?..."
    ]
    content_type = "image/jpeg"

    print("Starting file upload...")
    success = upload_file_in_chunks(file_path, upload_urls, content_type)

    if success:
        print("File upload completed successfully!")
    else:
        print("File upload failed!")
```

## 업로드 흐름 요약

#### 업로드 방법 선택

원격 업로드(URL을 통해 액세스할 수 있는 파일) 또는 로컬 업로드(시스템에 있는 파일) 중에서 선택

#### 파일 생성 요청

필요한 메타데이터로 파일 리소스를 생성하기 위한 초기 요청 수행

#### 업로드 URL 처리

로컬 업로드의 경우 반환된 upload\_urls(단일 또는 여러 파트)를 처리합니다.

#### 파일 콘텐츠 업로드

적절한 헤더를 포함한 PUT 요청을 사용하여 제공된 URL에 파일 콘텐츠를 업로드합니다.

#### 업로드 확인

파일 상태를 확인하여 업로드와 처리가 성공적으로 완료되었는지 확인합니다.

> **Info**
>
> **다음 단계**: 파일이 업로드되면 반환된 파일 ID를 활용해 Frame.io V4 API로 코멘트를 추가하거나, 공유를 생성하거나, 기타 작업을 수행할 수 있습니다.