---
title: "Confirm Presigned Upload"
method: POST
path: "/upload/confirm"
tags: ["upload"]
---

# Confirm Presigned Upload

`POST /upload/confirm`

## Request

- Base URL: `https://api.seal.net` (the document declares no server; this is the origin it was published from)
- URL: `https://api.seal.net/upload/confirm`
- Auth: none declared

Step 2: Confirm a direct upload. The file is verified HERE.

One HEAD against storage: the object exists and has the size the row
authorizes → `verified` in the same transaction, signed `file_verified`
event included. No queue and no polling on this path, and the server
never reads the object (audit/SPEC-UPLOAD-SCALE.md §3).

Status flow:
    pending → verified                      (the normal case)
    pending → pending_verification → …      (storage could not be asked:
                                             the durable worker repeats
                                             the same check)

Security:
    - SEAL: Requires X-Owner-Token header
    - AEON/Vault: Requires JWT Bearer token + org membership

## Request body

- ConfirmUploadRequest: Confirm upload completed request: the row by its id (C1 Р6, Р24).
  - `seal_id` string, required: Seal ID (8-char base64url)
  - `file_id` string, uuid, required: The file row from registration
  - `on_conflict` 'fail' | 'keep_both': A version whose base another version closed first: 412, or keep as a second head

## Response `200`

Successful Response

- ConfirmUploadResponse: Upload confirmation response
  - `version_of` string, nullable
  - `head` boolean, nullable
  - `conflict_with` string, nullable
  - `status` string, required
  - `message` string, nullable
  - `verified` boolean
  - `size` integer

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/seal/apis/seal-api.md) · [All operations](https://skmtc.dev/seal/apis/seal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/seal/apis/seal-api/revisions/68460cfa1957?raw)
