publ betaReference (MCP guide)
Open publ console

content_file_upload

# content_file_upload

Upload original bytes for a supported content asset, then use the returned URL in a separate editor.

Read the [shared content contract](../guides/content-apps.md) for authorization, app identity, result interpretation and recovery.

## Input

Require channelCode, exact installed pAppCode, requestId, purpose and file `{filename,base64,contentType?}`. There is **no expectedRevision**: this operation uploads bytes rather than editing a post. dryRun defaults to false and validates the file/purpose without issuing a credential or uploading.

filename is a basename of 1–240 characters, without paths, colon or control characters, and cannot be blank, `.` or `..`. base64 must be canonical and decode to nonempty original bytes. A data URL, remote URL, local path or caller-declared file metadata is not accepted. Optional contentType is one MIME type; it must match recognized images/MP3. Arbitrary attachment/resource files default to application/octet-stream. No remote source file is fetched.

## Purpose and decoded-byte limits

| purpose | Supported family | Maximum bytes |
| --- | --- | --- |
| attachment | A00002 notices, A00003 free boards | 30 × 1024 × 1024 |
| resource | B00012 | 200000000 |
| photobook_image / photobook_audio | B00005 | 19999999 each |
| post_thumbnail | B00001 / B00012 | 2 × 1024 × 1024 / 19999999 |
| post_cover | B00001 | 10 × 1024 × 1024 |
| series_thumbnail | B00001 / B00012 | 2 × 1024 × 1024 / 3 × 1024 × 1024 |
| series_logo | B00005 | 3 × 1024 × 1024 |
| series_cover | B00001, B00005, B00012 | 10 × 1024 × 1024 |
| outlink_image / welcome_image | B00002 / B00006 | floor(29.9 × 1024 × 1024) |
| board_cover | A00003, B00001 / exact B9xx01 | 10 × 1024 × 1024 |
| timeline_image | A00001 / exact A9xx01 | 9999999 original input; 10000000 normalized output bridge bound |
| timeline_video | A00001 / exact A9xx01 | 30000000 explicit bridge processing bound |

Supported aliases retain their exact installed identity. Ordinary image purposes recognize PNG/JPEG/GIF; photobook audio recognizes MP3 and requires existing Z00006 availability. Timeline image/video purposes require the trusted processing capabilities described below. Other video, question media and inline rich-editor uploads are unsupported. The schema's overall envelope does not override smaller purpose-specific limits.

## Result and recovery

CONTENT_FILE_UPLOADED returns asset metadata, location and taskId, with contentSaved:false. Resource uploads also return newResourceDefaults (filename-derived title, source default thumbnail and unpublished state). Use location with the appropriate post, series, outlink, welcome or taxonomy editor after a fresh read. Retain existing file URLs when replacing a complete attachment list. Upload alone does not create/publish content or prove public readability.

Use taskType `content-upload`. Storage must acknowledge the exact SHA-256; credentials and object writes are dispatched at most once. Phases are grant-sent, upload-sent, uploaded and verified. Unknown grant/storage outcomes remain CONTENT_UPLOAD_OUTCOME_UNVERIFIED, and resume never requests another credential or sends bytes. It can finish an already acknowledged uploaded checkpoint. File bytes are not persisted in the journal; an exact upload retry still supplies the same bytes and purpose. Unreferenced objects may remain; no automatic deletion or content-save retry is performed. Completed replay is historical. Storage acknowledgement does not prove rendering, playback or business attachment success.

## Input example

This is an input illustration, not a recorded call. Replace the channel and exact installed app with values from the matching authorized read. This uploader takes no revision or selected content ID. A dry run does not save changes.

```json
{
  "channelCode": "selected-channel",
  "pAppCode": "A00002",
  "requestId": "example-upload-001",
  "purpose": "attachment",
  "file": {
    "filename": "example.txt",
    "base64": "SGVsbG8=",
    "contentType": "text/plain"
  },
  "dryRun": true
}
```

## Article category cover upload

It adds no tool or task type. Supply original PNG/JPEG/GIF bytes, at most 10 × 1024 × 1024 bytes inclusive.

The common upload transport and content-upload recovery contract remain unchanged. The credential request uses the original basename. The article cover's storage Content-Disposition follows the generic file helper: attachment, filename stem truncated to 80 characters with the original extension retained. Existing free-board image disposition is unchanged.

CONTENT_FILE_UPLOADED still returns contentSaved:false. Its exact article categories-list parent asks the user to select the intended category and cover editor; no category ID is guessed and this is not a detail link. Read [content_taxonomy_get](content_taxonomy_get.md) for that category after the upload, then [save coverImageSrc separately](content_taxonomy_apply.md#save-an-uploaded-article-category-cover) with the fresh category revision. An upload dry run provides no uploaded location to save.

Unknown grant/PUT outcomes remain uncertain and cannot be resent through exact retry or resume. A later category-save failure can leave an unreferenced object. Restoring the original category cover URL with a fresh revision does not delete the new object; object deletion and automatic cleanup are unavailable.

```json
{
  "channelCode": "selected-channel",
  "pAppCode": "B00001",
  "requestId": "article-cover-upload-001",
  "purpose": "board_cover",
  "file": {
    "filename": "category-cover.png",
    "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aDWQAAAAASUVORK5CYII=",
    "contentType": "image/png"
  },
  "dryRun": true
}
```

## Timeline file processing

Use exact A00001 or A9xx01 with `timeline_image` or `timeline_video`. If the trusted processor is missing or rejects the bytes, no credential grant or storage upload occurs. A Timeline dry run runs inspection/conversion but makes no API grant, upload or post mutation. It does not reserve the normalized output.

`timeline_image` accepts original PNG/JPEG under 10,000,000 bytes. The trusted
host decodes/re-encodes the file as PNG; the domain checks source digest/length,
actual output digest/length/MIME/name/header and absence of metadata chunks. The
PNG output limit is a separate 10,000,000-byte bridge bound. Host image formats,
pixel count, bit depth, orientation and color-profile policy impose additional
processing constraints. HEIC/HEIF, animation and the original chooser's full
format set are not advertised as supported. Original source conversion sometimes
retains JPEG while its service labels bytes PNG; this bridge's actual PNG
normalization is an explicit behavior difference, not MIME-only relabeling.

`timeline_video` accepts MP4/M4V, MOV or Matroska with matching MIME and an
explicit bridge cap of 30,000,000 bytes. This is not a claim that the active
Timeline chooser enforces its unused VIDEO_MAX_SIZE constant. The existing
trusted host probe must inspect the exact uploaded bytes. Domain validation
requires duration at most 60 seconds without rounding down, and a diagonal
resolution at least that of 640 by 360. No caller-supplied duration, dimensions,
file path or video URL can replace this inspection. Host format/decode limits
remain bridge limits; VOD-specific aspect/frame-rate/storage policy is not
automatically applied as a Timeline rule.

The result includes `sourceAsset`, processed `asset` and `timelineMedia` evidence.
The request fingerprint uses original bytes. After a grant/upload boundary is
saved, retry/resume reads that durable record without converting, probing,
requesting credentials or sending bytes again, even if the processor is then
unavailable. Journals contain metadata, never file bytes or credentials. A
verified storage checksum still establishes neither image rendering nor video
encoding/post identity/playback. The Timeline posts-list parent requires a
separate editor action. An upload itself never creates a candidate or post.