Skip to main content
Core.Today
가격

File Upload & Storage

파일 업로드, 검색, 메타데이터 관리를 위한 Storage API입니다.

파일 업로드가 필요한 경우

  • Image-to-Image: 참조 이미지 기반 이미지 편집/변환
  • Image-to-Video: 첫 프레임 이미지로 비디오 생성
  • Voice Cloning: 음성 복제를 위한 샘플 오디오
  • ControlNet: 포즈/깊이 맵 등 제어 이미지
추천

간편 업로드 (Multipart)

POST /predictions/upload를 사용하면 파일 업로드와 예측 요청을 한 번의 API 호출로 처리할 수 있습니다. 별도로 presigned URL을 발급받거나 S3에 직접 업로드할 필요가 없습니다.

파일 필드 규칙

file:<input_key> 형식으로 파일 필드명을 지정하면, 업로드된 파일의 URL이 자동으로 input[input_key]에 주입됩니다.

파일 필드명결과
file:imageinput["image"] = "https://..."
file:image (x2)input["image"] = ["url1", "url2"]

cURL

# 단일 파일 - Image-to-Image
curl -X POST https://api.core.today/v1/predictions/upload \
  -H "X-API-Key: cdt_your_api_key" \
  -F "model=flux-kontext-pro" \
  -F 'input={"prompt":"change background to a beach sunset"}' \
  -F "file:image_url=@photo.png"

# 복수 파일 - 같은 키로 여러 파일 전송
curl -X POST https://api.core.today/v1/predictions/upload \
  -H "X-API-Key: cdt_your_api_key" \
  -F "model=flux-kontext-pro" \
  -F 'input={"prompt":"combine these images"}' \
  -F "file:image_url=@photo1.png" \
  -F "file:image_url=@photo2.png"

Python

import requests, json

with open("photo.png", "rb") as f:
    response = requests.post(
        "https://api.core.today/v1/predictions/upload",
        headers={"X-API-Key": "cdt_your_api_key"},
        data={
            "model": "black-forest-labs/flux-kontext-pro",
            "input": json.dumps({"prompt": "change background to a beach sunset"}),
        },
        files={"file:image_url": ("photo.png", f, "image/png")},
    )

job = response.json()
print(job["job_id"])  # 이후 GET /predictions/{job_id}로 결과 조회

JavaScript

const formData = new FormData();
formData.append("model", "black-forest-labs/flux-kontext-pro");
formData.append("input", JSON.stringify({ prompt: "change background to a beach sunset" }));
formData.append("file:image_url", fileInput.files[0]);

const response = await fetch("https://api.core.today/v1/predictions/upload", {
  method: "POST",
  headers: { "X-API-Key": "cdt_your_api_key" },
  body: formData,
});

const job = await response.json();
console.log(job.job_id);

Form 필드

필드타입필수설명
modelstringYes모델 ID
inputstring (JSON)No모델 입력 JSON 문자열 (기본: "{}")
is_publicstringNo"true" 또는 "false" (기본: "false")
output_folderstringNo결과물 저장 폴더 경로
webhook_urlstringNo완료 시 호출할 Webhook URL
file:<input_key>fileNo업로드할 파일 (최대 50MB/파일, 같은 키 복수 가능)

참고

  • 파일당 최대 크기는 50MB입니다.
  • 응답 형식은 POST /predictions와 동일합니다. 이후 GET /predictions/{job_id}로 결과를 조회하세요.
  • 업로드된 파일은 S3 스토리지에 저장되며, 7일간 접근 가능한 CDN URL이 생성됩니다.

Presigned URL 방식 (고급)

대용량 파일이나 업로드 진행률 표시가 필요한 경우, 아래 3단계 방식을 사용할 수 있습니다. 파일을 미리 업로드해두고 여러 prediction에서 재사용하려는 경우에도 유용합니다.

1

Presigned URL 발급

먼저 파일 업로드를 위한 presigned URL을 발급받습니다. 이 시점에 파일 메타데이터가 스토리지에 등록됩니다.

curl -X POST https://api.core.today/v1/files/upload-url \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"filename": "reference_image.png", "folder": "inputs"}'

메타데이터 저장

커스텀 메타데이터를 함께 저장할 수 있습니다 (최대 10KB):

curl -X POST https://api.core.today/v1/files/upload-url \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d {
    "filename": "data",
    "folder": "projects/my-project",
    "metadata": {
      "description": "프로젝트 데이터",
      "tags": ["dataset", "training"],
      "version": "1.0"
    }
  }

응답 예시

{
  "upload_url": "https://s3.ap-northeast-2.amazonaws.com/files.core.today",
  "upload_fields": {
    "Content-Type": "image/png",
    "key": "aiapi/f04423dfab11/inputs/1765720407215_reference_image.png",
    "x-amz-algorithm": "AWS4-HMAC-SHA256",
    "x-amz-credential": "ASIA.../20251214/ap-northeast-2/s3/aws4_request",
    "x-amz-date": "20251214T120000Z",
    "x-amz-security-token": "IQoJb3JpZ2luX2VjEG0a...",
    "policy": "eyJleHBpcmF0aW9uIjoiMjAyNS0xMi0xNFQxMzowMDowMFoiLCJjb25kaXRpb25zIjpbey...",
    "x-amz-signature": "e6444e667072a27fd5589241803c8abf..."
  },
  "file_url": "https://files.core.today/aiapi/.../reference_image.png?Expires=...&Signature=...&Key-Pair-Id=...",
  "object_key": "aiapi/f04423dfab11/inputs/1765720407215_reference_image.png",
  "folder": "inputs"
}

스토리지 쿼터 초과 (403)

팀이 플랜별 스토리지 쿼터(위 표)를 초과한 상태에서 POST /files/upload-url을 호출하면 403과 함께 storage_quota_exceeded 코드가 반환됩니다. 이는 파일당 50MB 제한과는 별개이며, 파일 하나가 아무리 작아도 팀 총 사용량이 한도를 넘으면 새 업로드가 거부됩니다. AI 예측 결과물은 이 쿼터로 차단되지 않습니다.

{
  "detail": {
    "message": "Storage limit exceeded. Limit: 5.0 GB, Used: 5.0 GB, Requested: 0 B",
    "code": "storage_quota_exceeded"
  }
}

message는 사람이 읽는 설명 문자열이며 바이트/파일 개수 한도 중 어느 쪽을 넘었는지에 따라 문구가 달라집니다(변동될 수 있음) — 분기 처리는 항상 code값(storage_quota_exceeded)으로 하세요. 해결: 오래된 파일을 삭제해 사용량을 확보하거나(GET /files/storage로 현재 사용량 확인), 상위 플랜으로 업그레이드하세요.

2

S3에 파일 업로드

발급받은 upload_url upload_fields를 사용하여 S3에 직접 파일을 업로드합니다.

cURL

# upload_fields의 모든 필드를 순서대로 추가하고, file은 마지막에 추가
curl -X POST "https://s3.ap-northeast-2.amazonaws.com/files.core.today" \
  -F "Content-Type=image/png" \
  -F "key=aiapi/f04423dfab11/inputs/1765720407215_reference_image.png" \
  -F "x-amz-algorithm=AWS4-HMAC-SHA256" \
  -F "x-amz-credential=ASIA.../20251214/ap-northeast-2/s3/aws4_request" \
  -F "x-amz-date=20251214T120000Z" \
  -F "x-amz-security-token=IQoJb3JpZ2luX2VjEG0a..." \
  -F "policy=eyJleHBpcmF0aW9uIjoiMjAyNS0xMi0xNFQxMzowMDowMFoiLCJjb25kaXRpb25zIjpbey..." \
  -F "x-amz-signature=e6444e667072a27fd5589241803c8abf..." \
  -F "file=@/path/to/reference_image.png"

JavaScript

async function uploadFile(file, apiKey) {
  // 1. Get presigned URL
  const urlResponse = await fetch(
    "https://api.core.today/v1/files/upload-url",
    {
      method: "POST",
      headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ filename: file.name, folder: "inputs" })
    }
  );
  const { upload_url, upload_fields, file_url } = await urlResponse.json();

  // 2. Upload to S3
  const formData = new FormData();
  Object.entries(upload_fields).forEach(([key, value]) => {
    formData.append(key, value);
  });
  formData.append("file", file); // file must be last!

  await fetch(upload_url, {
    method: "POST",
    body: formData
  });

  // 3. Return the CDN URL (use this in prediction requests)
  return file_url;
}

Python

import requests

def upload_file(filepath, api_key, folder="inputs"):
    filename = filepath.split("/")[-1]

    # 1. Get presigned URL
    url_response = requests.post(
        "https://api.core.today/v1/files/upload-url",
        headers={
            "X-API-Key": api_key,
            "Content-Type": "application/json"
        },
        json={"filename": filename, "folder": folder}
    )
    data = url_response.json()

    # 2. Upload to S3
    with open(filepath, "rb") as f:
        files = {"file": (filename, f)}
        requests.post(
            data["upload_url"],
            data=data["upload_fields"],
            files=files
        )

    # 3. Return the CDN URL (use this in prediction requests)
    return data["file_url"]

중요

  • file 필드는 반드시 마지막에 추가해야 합니다.
  • 모든 upload_fields 값을 그대로 전달해야 합니다.
3

모델 입력에 사용

업로드 완료 후 file_url을 모델의 입력 파라미터에 사용합니다.

Image-to-Image (FLUX Kontext)

curl -X POST https://api.core.today/v1/predictions \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "black-forest-labs/flux-kontext-pro",
    "input": {
      "prompt": "change the background to a beach sunset",
      "image_url": "https://cdn.core.today/inputs/abc123/reference_image.png"
    }
  }'

Image-to-Video (Kling)

curl -X POST https://api.core.today/v1/predictions \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kwaivgi/kling-v2.1",
    "input": {
      "prompt": "camera slowly zooms in, gentle wind blowing",
      "image": "https://cdn.core.today/inputs/abc123/first_frame.jpg",
      "duration": 5
    }
  }'

Voice Cloning (Fish Speech)

curl -X POST https://api.core.today/v1/predictions \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d {
    "model": "minimax/speech-02-turbo",
    "input": {
      "text": "이 문장은 업로드한 음성과 똑같은 목소리로 읽힙니다.",
      "reference_audio": "https://cdn.core.today/inputs/abc123/voice_sample.wav"
    }
  }

Storage API 엔드포인트

파일 업로드 외에도 스토리지 관리, 검색, 메타데이터 관리를 위한 다양한 API를 제공합니다.

메서드엔드포인트설명
업로드
POST/files/upload-urlPresigned URL 발급
스토리지 관리
GET/files/storage사용량 조회 (용량, 파일 수, 타입별 분류)
GET/files/storage/files파일 목록 조회 (페이지네이션, 폴더 필터)
GET/files/storage/file/{object_key}단일 파일 조회 (메타데이터 + 다운로드 URL)
GET/files/storage/folders폴더 목록 조회 (파일 수, 크기)
POST/files/storage/folder폴더 생성 (빈 폴더 미리 생성)
파일 관리
PATCH/files/storage/file/metadata메타데이터 수정
POST/files/storage/file/public공개/비공개 설정
DELETE/files/storage/file파일 삭제
검색
POST/files/storage/search메타데이터 기반 파일 검색
GET/files/storage/distinct/{field}필드별 고유값 조회
GET/files/storage/schema/fields검색 가능한 필드 목록

스토리지 사용량 조회

현재 팀의 스토리지 사용량을 조회합니다.

GET /files/storage
curl -X GET "https://api.core.today/v1/files/storage" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "total_bytes": 52428800,
  "total_mb": 50.0,
  "file_count": 127,
  "formatted_size": "50.0 MB",
  "by_content_type": [
    {"content_type": "image/png", "size": 31457280, "count": 85},
    {"content_type": "video/mp4", "size": 15728640, "count": 12},
    {"content_type": "audio/wav", "size": 5242880, "count": 30}
  ]
}

응답 필드

필드타입설명
total_bytesinteger총 사용량 (bytes)
total_mbfloat총 사용량 (MB)
file_countinteger총 파일 수
formatted_sizestring포맷된 사용량 (예: "50.0 MB")
by_content_typearray콘텐츠 타입별 사용량 분류

파일 목록 조회

업로드된 파일 목록을 페이지네이션과 함께 조회합니다.

GET /files/storage/files

쿼리 파라미터

파라미터타입설명
folderstring폴더 경로로 필터링 (선택)
limitinteger반환할 파일 수 (기본값: 50)
offsetinteger건너뛸 파일 수 (기본값: 0)
url_expirationinteger다운로드 URL 만료 시간 (초). 300~15,552,000 (5분~180일). 기본값: 604,800 (7일)
# 기본 조회 (7일 만료 URL)
curl -X GET "https://api.core.today/v1/files/storage/files?folder=inputs&limit=10" \
  -H "X-API-Key: cdt_your_api_key"

# 1시간 만료 URL로 조회
curl -X GET "https://api.core.today/v1/files/storage/files?folder=inputs&limit=10&url_expiration=3600" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "files": [
    {
      "filename": "photo.png",
      "file_size": 1048576,
      "content_type": "image/png",
      "uploaded_at": "2025-12-14T10:00:00Z",
      "object_key": "aiapi/team123/inputs/1734175200000_photo.png",
      "folder": "inputs",
      "expires_at": "2025-12-21T10:00:00Z",
      "file_url": "https://files.core.today/..."
    }
  ],
  "total_count": 42
}

단일 파일 조회

object key를 사용하여 단일 파일의 메타데이터와 다운로드 URL을 조회합니다.

GET /files/storage/file/{object_key}

object_key는 URL path에 직접 포함됩니다. S3 REST API와 동일한 방식입니다.

쿼리 파라미터

파라미터타입설명
url_expirationinteger다운로드 URL 만료 시간 (초). 300~15,552,000 (5분~180일). 기본값: 604,800 (7일)
# 기본 조회 (7일 만료 URL)
curl -X GET "https://api.core.today/v1/files/storage/file/aiapi/team123/inputs/1734175200000_photo.png" \
  -H "X-API-Key: cdt_your_api_key"

# 5분 만료 URL로 조회
curl -X GET "https://api.core.today/v1/files/storage/file/aiapi/team123/inputs/1734175200000_photo.png?url_expiration=300" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "filename": "photo.png",
  "file_size": 1048576,
  "content_type": "image/png",
  "uploaded_at": "2025-12-14T10:00:00Z",
  "object_key": "aiapi/team123/inputs/1734175200000_photo.png",
  "folder": "inputs",
  "status": "uploaded",
  "expires_at": "2025-12-21T10:00:00Z",
  "file_url": "https://files.core.today/...",
  "metadata": {"project": "avatar-gen", "tags": ["portrait"]},
  "is_public": false,
  "public_url": null
}

폴더 목록 조회

스토리지의 폴더 구조를 조회합니다. 각 폴더의 파일 수와 총 크기를 포함합니다.

GET /files/storage/folders
curl -X GET "https://api.core.today/v1/files/storage/folders" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "folders": [
    {"name": "inputs", "path": "inputs", "file_count": 85, "total_size": 31457280},
    {"name": "outputs", "path": "outputs", "file_count": 30, "total_size": 15728640},
    {"name": "projects", "path": "projects", "file_count": 12, "total_size": 5242880}
  ]
}

폴더 생성

파일 업로드 전에 빈 폴더를 미리 생성할 수 있습니다. 이미 존재하는 폴더를 생성하면 기존 폴더를 반환합니다.

POST /files/storage/folder
docs.fileUpload.createFolder.code
파라미터타입설명
folder_namestring (필수)폴더 이름 (1~255자, 특수문자 제한)
parent_folderstring (선택)상위 폴더 경로 (비어있으면 루트)

파일 검색 API

업로드된 파일을 다양한 조건으로 검색할 수 있습니다.

POST /files/storage/search

요청 파라미터

파라미터타입설명
filtersobject검색 조건 (메타데이터 필드 기반)
sort_bystring정렬 기준 필드 (기본값: created_at)
sort_orderstring"asc" 또는 "desc" (기본값: desc)
pageinteger페이지 번호 (기본값: 1)
page_sizeinteger페이지당 결과 수 (기본값: 20, 최대: 100)
url_expirationinteger다운로드 URL 만료 시간 (초). 300~15,552,000 (5분~180일). 기본값: 604,800 (7일)

검색 예제

# 최근 업로드된 PNG 파일 검색
curl -X POST https://api.core.today/v1/files/storage/search \
  -H "X-API-Key: cdt_your_api_key" \
  -H "Content-Type: application/json" \
  -d {
    "filters": {
      "content_type": "image/png",
      "folder": "inputs"
    },
    "sort_by": "created_at",
    "sort_order": "desc",
    "page_size": 10
  }

응답 예시

{
  "files": [
    {
      "object_key": "aiapi/team123/inputs/1734175200000_photo.png",
      "filename": "photo.png",
      "content_type": "image/png",
      "size": 1048576,
      "folder": "inputs",
      "created_at": "2025-12-14T10:00:00Z",
      "url": "https://files.core.today/...",
      "metadata": {
        "project": "avatar-gen",
        "tags": ["portrait", "input"]
      }
    }
  ],
  "total": 42,
  "page": 1,
  "page_size": 10,
  "total_pages": 5
}

검색 가능한 메타데이터 필드

40개의 인덱싱된 필드를 사용하여 파일을 검색할 수 있습니다.

Identity 필드

file_id - 파일 고유 ID
object_key - S3 객체 키
filename - 원본 파일명
team_id - 팀 ID
user_id - 사용자 ID

Time 필드

created_at - 생성 시간
updated_at - 수정 시간
expires_at - 만료 시간

Source 필드

source - 출처 (upload/prediction)
source_job_id - 원본 작업 ID
source_model - 생성 모델명
upload_ip - 업로드 IP

Object 필드

content_type - MIME 타입
size - 파일 크기 (bytes)
extension - 확장자
folder - 폴더 경로
checksum - MD5 해시

Classification 필드

category - 카테고리
subcategory - 서브카테고리
tags - 태그 배열
labels - 라벨 배열
project - 프로젝트명
environment - 환경 (dev/prod)

Status 필드

status - 상태 (pending/active/archived)
visibility - 공개 범위
is_processed - 처리 완료 여부
is_archived - 아카이브 여부

Metrics 필드

width - 이미지/비디오 너비
height - 이미지/비디오 높이
duration - 오디오/비디오 길이(초)
frame_count - 비디오 프레임 수
sample_rate - 오디오 샘플레이트
bit_depth - 오디오 비트심도

AI/ML Context 필드

prompt - 생성 프롬프트
negative_prompt - 네거티브 프롬프트
seed - 랜덤 시드
steps - 생성 스텝 수
cfg_scale - CFG 스케일
model_version - 모델 버전

Compliance 필드

retention_days - 보관 기간
legal_hold - 법적 보존 여부
classification_level - 보안 등급

고유값 조회 API

특정 필드의 고유값 목록을 조회합니다. 필터링 UI 구성에 유용합니다.

GET /files/storage/distinct/{field}
# 사용된 모든 폴더 목록 조회
curl -X GET "https://api.core.today/v1/files/storage/distinct/folder" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "field": "folder",
  "values": ["inputs", "outputs", "projects/avatars", "projects/backgrounds"],
  "count": 4
}

지원 필드

folder, content_type, extension, category, project, tags, source_model, status

스키마 필드 조회 API

검색 가능한 모든 필드와 타입 정보를 조회합니다.

GET /files/storage/schema/fields
curl -X GET "https://api.core.today/v1/files/storage/schema/fields" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "fields": [
    {"name": "file_id", "type": "keyword", "searchable": true},
    {"name": "filename", "type": "text", "searchable": true},
    {"name": "created_at", "type": "date", "searchable": true},
    {"name": "size", "type": "long", "searchable": true},
    {"name": "tags", "type": "keyword", "searchable": true, "array": true}
  ],
  "total_fields": 40
}

메타데이터 수정 API

파일의 메타데이터를 업데이트합니다. 기존 메타데이터와 병합됩니다.

PATCH /files/storage/file/metadata
docs.fileUpload.metaMod.code

주의사항

  • 시스템 필드(file_id, team_id, created_at 등)는 수정 불가
  • 메타데이터 전체 크기는 10KB를 초과할 수 없음

파일 삭제 API

파일과 메타데이터를 영구 삭제합니다.

DELETE /files/storage/file
curl -X DELETE "https://api.core.today/v1/files/storage/file?object_key=aiapi/team123/inputs/1734175200000_photo.png" \
  -H "X-API-Key: cdt_your_api_key"

# 응답 예시
{
  "success": true,
  "deleted_object_key": "aiapi/team123/inputs/1734175200000_photo.png",
  "deleted_at": "2025-12-14T12:00:00Z"
}

경고

  • 삭제된 파일은 복구할 수 없습니다
  • 자신의 팀에 속한 파일만 삭제할 수 있습니다

SDK 예제

Python - 파일 검색

import requests

API_KEY = "cdt_your_api_key"
BASE_URL = "https://api.core.today/v1"

def search_files(filters, page=1, page_size=20):
    """파일을 검색합니다."""
    response = requests.post(
        f"{BASE_URL}/files/storage/search",
        headers={
            "X-API-Key": API_KEY,
            "Content-Type": "application/json"
        },
        json={
            "filters": filters,
            "page": page,
            "page_size": page_size,
            "sort_by": "created_at",
            "sort_order": "desc"
        }
    )
    return response.json()

# 예: PNG 이미지 검색
results = search_files({
    "content_type": "image/png",
    "folder": "inputs"
})

for file in results["files"]:
    print(f"{file['filename']} - {file['size']} bytes")

# 예: 특정 프로젝트의 파일 검색
project_files = search_files({
    "project": "avatar-gen",
    "tags": ["approved"]
})

JavaScript - 파일 검색

const API_KEY = "cdt_your_api_key";
const BASE_URL = "https://api.core.today/v1";

async function searchFiles(filters, options = {}) {
  const { page = 1, pageSize = 20, sortBy = "created_at", sortOrder = "desc" } = options;

  const response = await fetch(`${BASE_URL}/files/storage/search`, {
    method: "POST",
    headers: {
      "X-API-Key": API_KEY,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      filters,
      page,
      page_size: pageSize,
      sort_by: sortBy,
      sort_order: sortOrder
    })
  });

  return response.json();
}

// 예: 최근 업로드된 이미지 검색
const images = await searchFiles({
  content_type: "image/png",
  folder: "inputs"
});

console.log(`Found ${images.total} files`);
images.files.forEach(file => {
  console.log(`${file.filename} - ${file.size} bytes`);
});

// 예: 특정 모델로 생성된 파일 검색
const generatedFiles = await searchFiles({
  source_model: "black-forest-labs/flux-schnell",
  created_at: { gte: "2025-12-01T00:00:00Z" }
});

메타데이터 설계 가이드

프로젝트별 관리

{
  "project": "avatar-generator",
  "category": "portraits",
  "environment": "production"
}

워크플로우 추적

{
  "status": "pending_review",
  "tags": ["needs-approval", "high-priority"],
  "assigned_to": "reviewer@company.com"
}

AI 생성 컨텍스트

{
  "source_model": "black-forest-labs/flux-schnell",
  "prompt": "A professional headshot",
  "seed": 12345,
  "steps": 28,
  "cfg_scale": 7.5
}

베스트 프랙티스

  • 일관된 네이밍: 모든 프로젝트에서 동일한 필드명 사용
  • 태그 활용: 여러 분류가 필요한 경우 tags 배열 활용
  • 환경 구분: dev/staging/production 환경별 파일 구분
  • 버전 관리: version 필드로 파일 버전 추적

파일 업로드 제한

파일 형식

모든 파일 형식 지원
이미지, 비디오, 오디오, 문서, 바이너리 등

최대 크기

50MB

플랜별 스토리지 제한

파일 업로드 및 스토리지 사용은 크레딧이 차감되지 않습니다. 단, 플랜에 따라 총 용량과 파일 수에 제한이 있습니다.

플랜파일 스토리지최대 파일 수DB 스토리지
Free1 GB1,000100 MB
Pro10 GB50,0005 GB
Team100 GB500,00050 GB
Enterprise1 TB10,000,000500 GB

현재 사용량은 대시보드의 Storage 페이지 또는 GET /files/storage API에서 확인할 수 있습니다.

파일 유효 기간

항목유효 기간설명
Presigned Upload URL7일URL 발급 후 7일 내 업로드 필요
업로드된 파일플랜별 (아래 표 참고)보관 기간은 URL 유효 기간과 무관합니다 — URL이 만료돼도 파일은 삭제되지 않으며, 보관 기간 내에는 언제든 재서명할 수 있습니다
다운로드 URL (기본)7일파일/결과 다운로드 URL 기본 만료 시간
다운로드 URL (커스텀, storage 조회)5분 ~ 180일storage 조회 엔드포인트(GET /files/storage/*)의 url_expiration 파라미터로 설정 (초 단위, 300~15,552,000)
재서명 URL (/files/sign)최대 7일POST /files/sign expiration은 604,800초(7일)로 캡됩니다

두 상한이 다른 이유: /files/sign 재서명은 현재 단계에서 최대 7일로 캡되어 있고, storage 조회 엔드포인트에서 다운로드 URL을 직접 생성할 때는 최대 180일까지 허용됩니다. 버그가 아니라 엔드포인트별 정책 차이이며, 어느 쪽이든 URL이 만료돼도 파일은 그대로이므로 object_key를 저장해 두면 언제든 다시 발급할 수 있습니다.

플랜파일 보관 기간
Free30일
Pro365일
Team / Enterprise무기한

중요

  • 업로드된 파일은 플랜별 보관 기간(위 표) 동안 유지되며, 그 전에는 직접 삭제하지 않는 한 사라지지 않습니다
  • 다운로드 URL이 만료돼도 파일은 그대로입니다 — object_key를 저장해 두면 POST /files/sign으로 새 URL을 재발급받을 수 있습니다
  • 스토리지 사용량은 대시보드 설정에서 확인할 수 있습니다

파일 재서명 (URL 갱신)

다운로드 URL은 기본 7일이 지나면 만료되지만, 파일 자체는 플랜별 보관 기간 동안 그대로 남아 있습니다. POST /files/sign으로 이 팀이 소유한 객체의 URL을 언제든 새로 발급받을 수 있습니다. URL 대신 object_key(또는 job_id)를 저장해 두는 것을 권장합니다 — URL은 만료되지만 object_key는 파일이 존재하는 한 유효합니다.

POST /files/sign
필드타입설명
object_keystring재서명할 S3 객체 키. url/job_id와 셋 중 정확히 하나만 지정
urlstring이전에 발급된 CloudFront URL (재서명용)
job_idstringprediction job ID — 해당 작업이 소유한 결과 파일 전체를 한 번에 재서명
expirationinteger (선택)요청 만료 시간(초). 최대 7일(604,800초)로 캡됨
docs.fileUpload.resign.code

소유권 확인 후에만 URL이 발급됩니다 — 다른 팀의 객체거나 존재하지 않는 키는 동일하게 404 file_not_found로 응답합니다 (파일 존재 여부가 유출되지 않도록). 리셀러 워크스페이스에서 X-Customer-Id 헤더와 함께 호출하면 그 고객에게 귀속된 파일만 재서명 대상이 됩니다.

이전 출력 재참조 (모델 체이닝)

이전 예측의 출력 파일을 다시 다운로드/업로드하지 않고 그대로 다음 예측의 input 값으로 넘길 수 있습니다. input 안에 이 팀이 소유한 https://files.core.today/... URL이 들어 있으면, 게이트웨이가 프로바이더로 보내기 전에 자동으로 새 URL로 재서명합니다. URL이 이미 만료됐어도 소유한 파일이면 그대로 동작합니다. 예를 들어 이미지 생성 결과를 비디오 모델의 입력 이미지로 바로 연결할 수 있습니다.

  • 이 팀이 소유하지 않은 파일이나 files.core.today가 아닌 URL은 변경 없이 그대로 통과합니다(에러 아님) — 아직 유효한 presigned URL이나 외부 URL도 그대로 사용할 수 있습니다.
  • 하나의 input에서 자동 재서명되는 소유 참조는 최대 20개입니다.

패턴 1 — 저장해 둔 URL을 그대로 넘기기 (자동 재서명)

docs.fileUpload.chaining.pattern1Code

패턴 2 — object_key를 저장해 두고 /files/sign으로 새 URL 발급 후 전달

docs.fileUpload.chaining.pattern2Code

패턴 1은 게이트웨이가 자동으로 재서명하므로 별도의 /files/sign 호출이 필요 없습니다. 패턴 2는 URL을 직접 검증·로깅하거나 클라이언트에 미리 전달해야 할 때 유용합니다. 두 경우 모두 파일은 다시 업로드되지 않습니다.

전체 예제 (Python)

import requests
import time

API_KEY = "cdt_your_api_key"
BASE_URL = "https://api.core.today/v1"

def upload_and_transform(image_path, prompt, project="default"):
    """이미지를 업로드하고 변환합니다."""

    # 1. Get presigned URL with metadata
    filename = image_path.split("/")[-1]
    url_response = requests.post(
        f"{BASE_URL}/files/upload-url",
        headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
        json={
            "filename": filename,
            "folder": f"projects/{project}/inputs",
            "metadata": {
                "project": project,
                "source": "upload",
                "original_filename": filename
            }
        }
    )
    url_data = url_response.json()

    # 2. Upload to S3
    with open(image_path, "rb") as f:
        requests.post(
            url_data["upload_url"],
            data=url_data["upload_fields"],
            files={"file": (filename, f)}
        )

    # 3. Create prediction with uploaded image
    pred_response = requests.post(
        f"{BASE_URL}/predictions",
        headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
        json={
            "model": "black-forest-labs/flux-kontext-pro",
            "input": {
                "prompt": prompt,
                "image_url": url_data["file_url"]
            }
        }
    )
    job_id = pred_response.json()["job_id"]

    # 4. Poll for result
    while True:
        result = requests.get(
            f"{BASE_URL}/predictions/{job_id}",
            headers={"X-API-Key": API_KEY}
        ).json()

        if result["status"] == "completed":
            return result["result"]
        elif result["status"] == "failed":
            raise Exception(result.get("error"))

        time.sleep(2)

# Usage
result = upload_and_transform(
    "/path/to/photo.jpg",
    "make it look like a watercolor painting",
    project="art-styles"
)
print(f"Result: {result}")