Arke
Build

Files & Content

How to attach, upload, and download binary content on the Arke network.

Overview

In Arke, any entity can have binary content attached. Files, documents, images, and other binary data are stored in R2 and referenced via the entity's properties.content map. This unified model means:

  • A file entity can have multiple content versions (v1, thumbnail, etc.)
  • A folder entity can have an attached cover image
  • A user entity can have a profile photo
  • Any custom entity type can store binary data

Content is stored using content-addressed identifiers (CIDs), ensuring integrity and enabling deduplication.

Content Map Structure

Content is stored in properties.content as a map of keys to content entries:

{
  "properties": {
    "content": {
      "v1": {
        "cid": "bafkrei...",
        "size": 1048576,
        "content_type": "application/pdf",
        "filename": "document.pdf",
        "uploaded_at": "2025-01-15T10:00:00Z"
      },
      "thumbnail": {
        "cid": "bafkrei...",
        "size": 10240,
        "content_type": "image/png",
        "uploaded_at": "2025-01-15T10:01:00Z"
      }
    }
  }
}

Each content entry contains:

FieldTypeDescription
cidstringContent identifier (computed from bytes)
sizenumberFile size in bytes
content_typestringMIME type
filenamestring?Original filename (for download headers)
uploaded_atstringISO 8601 timestamp

Uploading Content

Upload binary content directly through the API:

POST /entities/{id}/content?key=v1&filename=document.pdf
Content-Type: application/pdf
Authorization: Bearer <token>

<binary file data>

Query parameters:

  • key (required) - Content key (e.g., "v1", "original", "thumbnail")
  • filename (optional) - Filename for Content-Disposition header on download

Response:

{
  "id": "01KFNR1234567890ABCDEFGH",
  "cid": "bafyrei_newversion...",
  "content": {
    "key": "v1",
    "cid": "bafkrei...",
    "size": 1048576,
    "content_type": "application/pdf",
    "filename": "document.pdf",
    "uploaded_at": "2025-01-15T10:00:00Z"
  },
  "prev_cid": "bafyrei_oldversion..."
}

The system:

  1. Streams content directly to R2 storage
  2. Computes the CID from file bytes
  3. Updates the entity with the new content entry
  4. Creates a new entity version

For large files, upload directly to R2 using a presigned URL:

Step 1: Compute CID client-side

Hash your file content using BLAKE3 to get a CID. Libraries like multiformats can help.

Step 2: Get presigned URL

POST /entities/{id}/content/upload-url
Content-Type: application/json
Authorization: Bearer <token>

{
  "cid": "bafkrei...",
  "content_type": "application/pdf",
  "size": 52428800
}

Response:

{
  "upload_url": "https://...",
  "expires_at": "2025-01-15T10:15:00Z"
}

Step 3: Upload directly to R2

PUT <upload_url>
Content-Type: application/pdf

<binary file data>

Step 4: Complete the upload

POST /entities/{id}/content/complete
Content-Type: application/json
Authorization: Bearer <token>

{
  "key": "v1",
  "cid": "bafkrei...",
  "size": 52428800,
  "content_type": "application/pdf",
  "filename": "large-file.pdf",
  "expect_tip": "bafyrei_current..."
}

Size Limits

Maximum file size is 500 MB. Files larger than this return HTTP 413.

Downloading Content

GET /entities/{id}/content?key=v1
Authorization: Bearer <token>

Query parameters (one optional):

  • key - Content key to download
  • cid - Content CID to download (alternative to key)

If neither is specified, returns the first content key alphabetically.

Response headers:

  • Content-Type: MIME type of the content
  • Content-Length: File size in bytes
  • Content-Disposition: attachment; filename="..." (if filename was set)

The response is streamed directly from R2 storage.

Managing Content

Adding Multiple Content Versions

Upload additional content with different keys:

# Upload original
POST /entities/{id}/content?key=original
Content-Type: image/png
<original image>

# Upload thumbnail
POST /entities/{id}/content?key=thumbnail
Content-Type: image/png
<thumbnail image>

# Upload WebP version
POST /entities/{id}/content?key=webp
Content-Type: image/webp
<webp image>

Renaming Content Keys

Rename a content key without re-uploading:

PATCH /entities/{id}/content
Content-Type: application/json
Authorization: Bearer <token>

{
  "old_key": "v1",
  "new_key": "original",
  "expect_tip": "bafyrei..."
}

Removing Content

Remove a content entry from the entity:

DELETE /entities/{id}/content?key=thumbnail&expect_tip=bafyrei...
Authorization: Bearer <token>

The R2 file is preserved for version history—only the metadata reference is removed.

Creating File Entities

While any entity can have content, the file type is optimized for file management:

POST /entities
Content-Type: application/json
Authorization: Bearer <token>

{
  "type": "file",
  "properties": {
    "label": "Moby Dick (PDF)",
    "description": "The complete novel"
  },
  "collection": "01KFNR0H0Q791Y1SMZWEQ09FGV"
}

Then upload content:

POST /entities/{id}/content?key=v1&filename=moby-dick.pdf
Content-Type: application/pdf
Authorization: Bearer <token>

<binary file data>

Uploading New Versions

To upload a new version of content, simply upload with a new key:

# Original upload
POST /entities/{id}/content?key=v1&filename=draft.pdf

# Revised version
POST /entities/{id}/content?key=v2&filename=final.pdf

Previous versions remain accessible via entity version history. You can also overwrite an existing key if you want to replace content in place.

Permission Actions

Content operations use standard entity permissions:

ActionDescription
entity:viewDownload content
entity:updateUpload, rename, or remove content

Best Practices

  1. Use meaningful keys - original, thumbnail, v1, processed are clearer than file1, file2

  2. Store metadata in properties - Put searchable metadata (title, author, etc.) in entity properties, not just in the filename

  3. Use presigned URLs for large files - Avoids streaming through the API worker

  4. Leverage multiple content slots - Store derivatives (thumbnails, transcoded versions) on the same entity

  5. Set filenames for downloads - Include the filename parameter so browsers save with the correct name

On this page