LibraryFilesv17 · Updated Report

Files

A file is a durable asset that belongs to an organization. Every member and agent with access to that organization sees the same files. Files carry the images that documents show inline, and they carry attachments for integrations such as Gmail. File bytes never enter model context: every method returns ids and metadata, and a read link hands the bytes to your runtime or to the person.

Where files live

Files belong to an organization, not to you and not to a document, so every method takes organizationId. Access follows document permissions, because files are document assets: listing and reading files needs document read, uploading needs document create, and deleting needs document manage. A principal that holds only document read, such as a narrow API key, sees only files that a document references. Files that no document references yet are a writer's workspace and stay invisible to read-only principals.

The six methods

  • listFiles({ organizationId }) returns the organization's files, each with fileId, filename, mimeType, sizeBytes, and createdAt, alongside usedBytes, maxBytes, fileCount, and maxFiles for the organization's capacity.

  • uploadFile({ organizationId, filename, contentBase64, mimeType }) stores bytes you already hold and returns { fileId, sizeBytes }. The base64 argument is capped at 128000 characters, which suits roughly 96 KB of content or less.

  • getUploadLink({ organizationId, filename, sizeBytes, mimeType }) mints a write-once upload URL and returns { fileId, url, expiresAtEpochSeconds }. PUT the bytes to url from your own host within fifteen minutes, or give the person the link to open in a browser when your environment cannot make HTTP requests. Use this for anything larger than a small upload, and for files the person holds rather than you.

  • getFileMetadata({ organizationId, fileId }) returns one file's filename, mimeType, sizeBytes, createdAt, and anchoredBy, the owners that currently anchor it: each document that references it, or the organization whose logo it is. This is how you check whether a file is in use before you delete it.

  • getReadLink({ organizationId, fileId }) mints a signed download URL and returns { fileId, url, expiresAtEpochSeconds }. The link is valid for fifteen minutes and serves the original bytes as an attachment. Fetch it from your own runtime or hand it to the person. Never paste file contents into model context.

  • deleteFile({ organizationId, fileId }) removes one file permanently and returns { fileId, deleted: true }. A file that a document references is refused; remove the reference first.

mimeType is optional on both upload paths and defaults to application/octet-stream. Set it correctly for images, because only a real image type renders inline in a document.

Showing an image in a document

A document refers to a file with an asset reference: the URI oddlynew-asset:<fileId> in the src of an image block. In Markdoc that is ordinary image syntax.

![Quarterly revenue chart](oddlynew-asset:0199c8f2-1b5e-7a41-9d2c-6f0a3b5e1c77 "Revenue by quarter, 2026")

Upload first, keep the fileId, then write the reference. The full flow in one script:

const organizationId = "0199c8f2-0000-7a41-9d2c-6f0a3b5e1c00"
const upload = await files.uploadFile({
  organizationId,
  filename: "revenue-q2.png",
  mimeType: "image/png",
  contentBase64: pngBase64,
})
return await documents.createDocument({
  organizationId,
  typeId: "00000000-0000-8000-8000-000000000000",
  title: "Q2 revenue review",
  draft: {
    markdoc: `# Q2 revenue review\n\n![Quarterly revenue chart](oddlynew-asset:${upload.fileId} "Revenue by quarter")\n`,
  },
})

The same reference works inside editDocument through insertBlock or replaceBlock. The document stores only the stable reference, never a URL, so the image keeps working across versions, copies, and link rotation.

The file must belong to the same organization as the document. A reference to a file that lives in another organization fails the write with "Document references an asset that does not exist in the same organization". A reference to a file that no longer exists anywhere is dropped from the reference set and the viewer shows a stable asset-unavailable state in its place; the write itself succeeds.

Raster images render inline: PNG, JPEG, GIF, and WebP. The viewer re-encodes and resizes them for the page, so the stored bytes are never delivered verbatim on the document origin. Supported audio files render inline through the browser's native audio player. HTML files render only through an explicit html block as described below. An image block shows only raster images: a ZIP, a video, a PDF, an SVG or any other file referenced from an image block renders as the asset-unavailable placeholder, even though the file exists. Every file that is not a raster image, audio, or embedded HTML belongs in an attachment block, described below. In a public document, referenced images and audio are public too, under the same visibility as the document text.

Playing audio in a document

An audio block refers to a same-organization file through the same stable asset URI used by images:

{% audio src="oddlynew-asset:<fileId>" title="Interview" caption="Episode one" /%}

src is required. title supplies the player's accessible label and caption adds visible context; both are optional. Supported MIME types are audio/aac, audio/flac, audio/mp4, audio/mpeg, audio/ogg, audio/wav, and audio/webm. Oddlynew renders native browser controls and preloads only metadata. Playback uses byte-range requests directly against Files in R2, so seeking works without a separate streaming service such as Mux. The original audio remains owned by Files and benefits from R2's delivery path.

Inside Oddlynew, the viewer uses short-lived member capabilities and renews them before expiry while preserving playback position and whether the audio was playing. In published content, the Content API keeps the stable asset reference in version.content and resolves the file id to an immutable public URL in assets.

See the Audio block demo for a working English MP3 generated with ElevenLabs, copied with its File into the public organization, and played directly in a document.

Embedding an HTML file

An html block embeds a self-contained HTML file through the same asset reference:

{% html src="oddlynew-asset:<fileId>" title="Revenue dashboard" height=560 /%}

src must reference a file in the same organization, uploaded with mimeType: "text/html" — only a genuine text/html file is served for embedding. title becomes the embed's caption and accessible name. height is the rendered height in pixels; omit it and the viewer shows a default fixed-height box whose content scrolls inside.

The file must be self-contained: one HTML document carrying its styles, scripts, and data inline. The embed resolves no external subresources — no CDN scripts, no external stylesheets, no remote images, no fetches. Embed small assets as data URIs when you need them. The html block is part of the standard Markdown vocabulary, so every type whose root uses the "markdown" sentinel accepts it without a type change.

Readers see the file in a sandboxed frame served from Oddlynew's separate user-content domain under a short-lived capability URL minted per read. Scripts inside the file run — an embed can be genuinely interactive — but the frame is isolated from the application: no access to the page around it, no cookies, no storage, no shared origin. The file renders on a white canvas exactly as it would opened directly in a browser, including when the app is in dark mode.

Embeds render for readers of the document inside Oddlynew. Published content read through the Content API carries the block and its file reference, but there is no public URL for the HTML file itself yet, so a headless site cannot frame the embed today. For what this block is good for — and the loop agents use to keep an embed current — see Live dashboards without serving infrastructure. For a video, a design file, or a post that lives on YouTube, Vimeo, Loom, Figma, or X, use the embed block instead: see Embedding external media.

A whole page that is one HTML file

An HTML page is a document of the platform type HTML page whose body is exactly one html block, and the reader shows the file edge to edge under the document bar, with no surrounding sheet, title or caption. When to make one rather than a document, an html block or a Lens: Choose a document, an HTML page or a Lens.

An HTML page shows knowledge and does not keep it: every fact, decision and number on it lives in the documents that own them, and search and link previews read only the page's title, never the file, so write anything that would exist only on the page into its document first.

The file runs in the same sandbox as every html block, with the same read channel, and the rules above apply unchanged: one self-contained text/html file with its styles, scripts, fonts and images inline, nothing loaded from elsewhere. Sharing, public organizations and versions work as for any document; version history and comparison show the file as a block on the sheet.

  1. Upload the file with files.uploadFile, or files.getUploadLink when it is larger, with mimeType: "text/html".

  2. Call documents.createDocument with the HTML page type 00000000-0000-8000-8000-000000000013 and the draft {% html src="oddlynew-asset:<fileId>" /%}.

  3. To update the page, upload the new file and point the block's src at it with documents.editDocument.

Give the page a title that says what it shows, since the title is how people and agents find it, and link the page from the document or Lens it serves. Discuss what the page shows on the document that owns it: a comment cannot be anchored inside the page, since a comment attaches to marked text and the file offers none.

Offering a file for download

An attachment block shows any same-organization file as a download: the reader sees its name and size and downloads it with one click. Use an attachment block to offer any file for download; for inline playback of an MP4 or WebM video, use a video block.

{% attachment src="oddlynew-asset:<fileId>" title="Quarterly report" /%}

src is required. title is an optional label shown instead of the stored filename. Each click re-authorizes the reader, so an attachment never places a permanent file URL in the page. To turn a wrongly used image block into a download, replaceBlock its key with the attachment tag; the block keeps its key. Before you finish a document with files, compare each referenced file's mimeType from getFileMetadata with its block: image blocks for image/png, image/jpeg, image/gif, image/webp; audio blocks for audio/*; html blocks for text/html; attachment blocks for everything else.

References anchor the file

When a document saves, Oddlynew records every asset reference in its content as an anchor on the file. Anchors are what getFileMetadata reports as anchoredBy, and they are what protects a file: deleteFile refuses an anchored file. Anchors follow the content exactly. When you remove the reference from the document, the next save releases the anchor. Archiving a document keeps its anchors; a deleted document releases them once it is purged. A file with no anchors is a workspace file: still listed, still downloadable, and free to delete.

Files are a store in their own right, not an appendage of documents. A file lives until you delete it: Oddlynew never deletes a file automatically, and losing your last anchor never marks a file for cleanup; it only makes the file deletable again. Deleting a document that referenced your CSV does not delete the CSV. When an agent replaces a file a document shows (an HTML page, a daily dashboard, a refreshed export), it uploads the new file and repoints the reference. The old file loses its anchor on the next save, but it is still the file earlier versions of the document show, so leave it in place unless you mean those versions to show it as unavailable. Old files count against the organization's storage quota.

Copying a document into another organization with organizations.planDocumentCopy copies the referenced files with it. The destination receives its own file ids and its own anchors, the copied content is rewritten to the new references, and the copied bytes count against the destination's quota.

Attaching a file to a Gmail draft

createDraft and updateDraft take attachments, and an entry of the form { fileId, filename } attaches an organization file with no Gmail read cost. filename is optional and overrides the stored name for the recipient. Upload first, keep the fileId, then reference it when you build the draft.

A draft holds up to 10 attachments and 5000000 bytes in total. An updateDraft that omits attachments produces a draft with no attachments at all, so send the full list again every time you revise one.

Limits worth knowing

  • File capacity belongs to the organization and grows with its plan. The default storage ceiling is 250 MiB for a free organization and 100 GiB for an organization funded by a Pro billing account; grants and individual overrides can change it, so read maxBytes from listFiles, while maxFiles is always null in Oddlynew. listFiles reports your organization's own numbers — usedBytes and maxBytes, fileCount and maxFiles — so read those instead of assuming a tier. Delete something before uploading when either ceiling is close; a copy into a full organization is refused the same way.

  • Each single file is also capped by type, the same on every plan: images and PDFs up to 10 MB, video and audio up to 90 MB, and 5 MB for everything else, plain text included.

  • A lapsed plan never deletes anything. Existing files stay readable, downloadable, and deletable; only new uploads are refused while the organization is over its ceiling.

  • mimeType must be a bare type and subtype such as application/pdf or image/png. A parameterized value such as text/plain; charset=utf-8 is refused, because it would store fine and then never attach.

  • Upload and read links expire after fifteen minutes. Mint a fresh one instead of storing them; the fileId is the durable handle.

  • A file is visible to everyone in the organization. Do not upload anything that organization should not hold.

  • Deletion is immediate and permanent. There is no archive step and no restore. A file that a document references cannot be deleted until the reference is gone.

Oddlynew PublicSign in

Referenced by