---
title: "Finalize an asset upload"
method: POST
path: "/assets/{id}/complete"
tags: ["Assets"]
---

# Finalize an asset upload

`POST /assets/{id}/complete`

Verifies the uploaded object exists in storage, enforces the plan size limit and storage quota, and marks the asset ready. For multipart uploads, supply the part etags to assemble the object first.

## Path parameters

- `id` string, required — Asset ID

## Request body

- object
  - `parts` object[] — Multipart part etags (required for multipart uploads)
    - `partNumber` integer, required — 1-based part index
    - `etag` string, required — ETag returned by R2 for the uploaded part

## Response `200`

Asset finalized and ready

- object
  - `data` object, required
    - `id` string, required — Asset ID (e.g., asset_abc123def456)
    - `url` string, required — Stable content URL — pass this as a job input; resolves to a presigned GET at dispatch
    - `orgId` string, required — Organization ID that owns this asset
    - `createdBy` string, nullable, required — User ID that created the asset
    - `lifecycle` string, required — ephemeral | persisted
    - `status` string, required — pending | uploading | ready | failed | expired
    - `source` string, required — upload | url | job_output
    - `kind` string, required — media | psd_template | font | other
    - `scope` string, required — org | system
    - `region` string, required — auto | eu
    - `etag` string, nullable, required — R2 etag recorded at finalize
    - `checksum` string, nullable, required — Client-declared sha256
    - `declaredSize` integer, nullable, required — Client-declared size at init
    - `sizeBytes` integer, nullable, required — Measured size at finalize
    - `contentType` string, nullable, required — MIME content type
    - `mediaType` string, nullable, required — video | image | audio | font | other
    - `filename` string, nullable, required — Sanitized display filename
    - `expiresAt` integer, nullable, required — Ephemeral TTL (Unix ms)
    - `metadata` string, nullable, required — JSON probe results
    - `createdAt` integer, required — Creation timestamp (Unix ms)
    - `updatedAt` integer, required — Last update timestamp (Unix ms)

## Other responses

- `400` — Multipart completion is missing part etags
- `401` — Unauthorized
- `402` — Storage quota exceeded
- `404` — Asset not found
- `409` — Asset is not in a finalizable state, or the upload was not found in storage
- `413` — Uploaded file exceeds the plan's size limit

---

[API](https://skmtc.net/rendobar/apis/rendobar-api.md) · [All operations](https://skmtc.net/rendobar/apis/rendobar-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/rendobar/rendobar-api/versions/d536c211f602/schema)
