Uploading files

POST /api/v1/files uploads one file with multipart/form-data. The public endpoint currently accepts files up to 100 MiB (104,857,600 bytes) and requires the upload scope plus the key owner's files.upload permission.

Request

FieldRequiredDescription
fileyesThe file. Its filename and content type come from this part.
collection_idnoUUID of a collection to add the file to. An inaccessible or missing collection leaves the file in the library only.

Content-Length is required. Accepted content types are image/*, video/*, application/pdf, text/plain, and application/octet-stream. Known image extensions—including common RAW formats, PSD, TIFF, HEIC, and HEIF—are normalized from the filename before validation.

bash
curl --fail-with-body \
  -X POST "$NEW_ARCHIVE_URL/api/v1/files" \
  -H "Authorization: Bearer $NEW_ARCHIVE_API_KEY" \
  -F "file=@sunset.jpg" \
  -F "collection_id=0198c9a0-7d3e-7c41-b7a2-3f9d1c2e4a5b"

Upload response

A successful upload returns 202 Accepted. The bytes are stored, but background processing may still be creating thumbnails and searchable data.

json
{
  "id": "0198c9a0-7d3e-7c41-b7a2-3f9d1c2e4a5b",
  "version_id": "0198c9a0-8a12-7e55-9c01-d4b6f7a8e9c0",
  "status": "processing"
}

Uploads over the limit return 413 payload_too_large. A full team storage quota returns 507 quota_exceeded.

Read status and metadata

GET /api/v1/files/:fileId accepts either the upload or search scope. Use it to poll an upload or retrieve one search result in detail.

bash
curl --fail-with-body \
  "$NEW_ARCHIVE_URL/api/v1/files/0198c9a0-7d3e-7c41-b7a2-3f9d1c2e4a5b" \
  -H "Authorization: Bearer $NEW_ARCHIVE_API_KEY"
json
{
  "id": "0198c9a0-7d3e-7c41-b7a2-3f9d1c2e4a5b",
  "status": "ready",
  "original_name": "sunset.jpg",
  "mime_type": "image/jpeg",
  "size_bytes": 2481931,
  "width": 4000,
  "height": 3000,
  "taken_at": "2026-06-30T18:41:02.000Z",
  "created_at": "2026-07-11T09:12:44.201Z",
  "thumbnail_url": "https://storage.example/signed-thumbnail"
}
FieldTypeDescription
idstringStable file UUID.
statusstringprocessing, ready, or failed.
original_namestringFilename supplied at upload.
mime_typestringNormalized content type.
size_bytesnumberStored original size in bytes.
widthnumber or nullPixel width when available.
heightnumber or nullPixel height when available.
taken_atstring or nullCapture time from metadata, as ISO 8601.
created_atstringUpload time, as ISO 8601.
thumbnail_urlstring or nullSigned thumbnail URL for ready files, valid for about one hour.

An unknown file ID—or one belonging to another team—returns 404 not_found. Original-file downloads are not part of API v1.

Poll until processing finishes

Poll no faster than once per second because each request counts toward the key's rate limit.

js
async function waitForFile(fileId) {
  const url = `${process.env.NEW_ARCHIVE_URL}/api/v1/files/${fileId}`
  for (;;) {
    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.NEW_ARCHIVE_API_KEY}` },
    })
    const body = await response.json()
    if (!response.ok)
      throw new Error(`${body.error.code}: ${body.error.message}`)
    if (body.status !== "processing") return body
    await new Promise((resolve) => setTimeout(resolve, 2000))
  }
}