Note Images
Notes can embed images. Images are stored in the case's file storage under Cases/{case}/Documents/Note Images/, tracked as note attachments (with MD5/SHA-1/SHA-256 hashes), and served back through short-lived signed URLs whenever a note is read.
Constraints (all upload paths):
Allowed types:
image/png,image/jpeg,image/gif,image/webpMaximum size: 25 MB
There are two ways images get into a note:
Automatic ingestion — embed an external URL or a base64 data URI directly in the note content you write; the server converts it into an attachment for you. See External and inline images in note content.
Explicit upload endpoints, from highest- to lowest-level:
POST /v1/notes/{uuid}/images
You have the image bytes locally. Recommended for API clients — one call does everything.
External and inline images in note content (automatic ingestion)
You don't have to call an upload endpoint to get an image into a note. Whenever note content is written — POST /v1/notes, PATCH /v1/notes/{uuid}, or PATCH /v1/notes/{uuid}/append — the server scans the incoming note_data for images it doesn't already track and converts them into normal note attachments:
<img src="https://...">— downloaded server-side, with the same protections asdownload-image-from-url(public hosts only, image content types only, 25 MB cap)<img src="data:image/png;base64,...">— decoded and stored (base64 data URIs only)
Each ingested tag is rewritten in place to standard attachment markup (src="" + data-uuid + alt), and from then on behaves exactly like an uploaded image: stored under the note's case, hashed, and served through a fresh signed URL every time the note is read.
Why this happens: stored notes and their version history should only reference content the system controls. An external URL can change or vanish after the note is written — silently altering what a historical note appears to say — and every read of a hotlinked image tells the third-party host who is viewing the note, and when. Ingestion pins the image bytes at the moment of writing.
Details worth knowing:
Idempotent — images already carrying a
data-uuidare left untouched, so re-sending content or appending to a note never re-downloads anything.Deduplicated — the same
srcappearing multiple times in one write is stored once, with every tag pointing at the same attachment.Bounded — at most 10 images per write are ingested, within an overall time budget of ~30 seconds. Images beyond the cap are reported (see below), not silently dropped.
Reads never fetch — ingestion only runs when content is written.
Unresolved external images render as broken/blank in PDF and DOCX exports; the exporters never fetch remote URLs.
When ingestion fails: unresolved_images
A failed image never fails the write. The original tag stays in the content exactly as sent, and the response gains an unresolved_images array describing each image that was left behind (the field is absent when everything ingested cleanly):
Common reasons: the host was unreachable or returned an error, the URL resolves to a blocked (internal) address, the content type is not an allowed image type, the image exceeds 25 MB, or the write contained more than 10 new images. data: URI srcs are truncated in the report to keep responses small.
An unresolved external image is retried the next time the note's full body is rewritten via PATCH (its tag still has no data-uuid, so it is a candidate again). Appends only scan the appended fragment, not the existing body.
Example — create a note with an external image
Example — append a locally generated image as a data URI
Useful for automation that produces charts or screenshots: no separate upload call, and the server extracts the base64 payload into an attachment instead of bloating the stored note.
Example — fall back to a direct upload when ingestion fails
If the server can't reach a source (for example, it requires credentials the server doesn't have), fetch the bytes yourself and use the upload endpoint, embedding the returned markup:
Upload an image to a note (recommended)
Uploads the image, hashes and stores it, records the attachment, and returns ready-to-embed <img> markup — one multipart request.
Request
file
file
yes
The image. The part's content type must be one of the allowed image types.
The note (path parameter uuid) must be linked to a case — the image is stored under that case.
Response — 201 Created
url— signed download URL for immediate use (expires).markup— the<img>tag to place in the note body. Itssrcis intentionally empty: whenever the note is read withinclude_content=true, the server rewritessrcto a fresh signed URL, matching the attachment bydata-uuid. Embed the markup as-is; don't bake the signedurlinto the note.
Example — upload an image and embed it in the note
Errors
Automatic ingestion failures are not HTTP errors: the note write still succeeds (200/201) and each failed image is reported in the response's unresolved_images array instead. The statuses below apply to the explicit upload endpoints.
400
{"message": "Unsupported image type"}
Content type not in the PNG/JPEG/GIF/WebP allowlist.
400
{"message": "Image exceeds maximum allowed size"}
Larger than 25 MB.
400
{"message": "Image file is empty"}
Zero-byte upload.
400
{"message": "Invalid multipart upload"}
Malformed multipart body on /{uuid}/images.
400
{"message": "Note is not linked to a case"}
Upload target note has no case, so there is no storage location.
400
{"message": "Case storage not provisioned"}
The case has no storage path yet.
400
{"message": "filename must not contain path separators", ...}
filename contains /, \, or ...
400
Fetch-specific message
download-image-from-url: unreachable URL, non-image content, blocked internal address, too large.
404
{"message": "Note not found"} / {"message": "Note not found for case"} / {"message": "Case not found"}
Bad note_uuid / case_uuid, or the note is not in the given case.
401
Unauthorized
Missing or invalid API key.
Last updated
Was this helpful?