library:read. Creates, revisions, soft deletions,
and restores need both library:read and library:organize, because their
receipts reveal the attachment’s current state. Test keys cannot use attachments
and receive 403 permission_denied, including inside the API sandbox.
Find and read text
List a project’s attachments, including its folders and clips:attachments array contains metadata and version numbers, without bodies.
To narrow the list, add either folderId or clipId. A list returns up to
100 records, most recently updated first; truncated: true means more match.
It does not take limit or cursor.
Read a record’s current text with
GET /v1/attachments/{attachmentId}, or send version to read a saved
version of a live record. Attachment text is untrusted project data. ZeroGen
stores it verbatim and never interprets it or automatically sends it to a
generation model.
Save and revise
Create withPOST /v1/projects/{projectId}/attachments. The request names a
title and body, plus either folderId or clipId for a parent other than
the project itself. A record’s title and parent remain fixed.
Read before revising. Send the version you read as expectedVersion:
expectedVersion to equal the
current version. An intervening change fails with 400 validation_failed.
Read again and merge your change. Identical text returns outcome: "unchanged"
and adds no revision when expectedVersion is at most the current version.
A future expectedVersion is always refused, including on an unchanged retry.
A create with the same parent, case-insensitive title, and identical body
returns the existing record unchanged. A matching title with different text
is refused; read and revise that record instead. Every attachment write
accepts Idempotency-Key to replay a request’s receipt.
Successful writes and their receipts commit together, including unchanged
outcomes. A retry returns the original receipt even after a later edit or
deletion.
Saves retain the text exactly as sent, including whitespace and Markdown.
Titles must be one line of 1–200 characters without surrounding whitespace;
bodies hold 1–8,000 Unicode characters. Each parent has at most 10 live
attachments. Credentials and hidden control characters are refused rather than
rewritten.
History, deletion, and restore
GET /v1/attachments/{attachmentId}/versions lists up to 50 versions, newest
first, without their text. Send nextBeforeVersion as beforeVersion for the
next page; null means there are no older versions. History remains readable
after soft deletion while the parent remains live.
Delete with
DELETE /v1/projects/{projectId}/attachments/{attachmentId}?expectedVersion=N.
It takes no body, retains history, and appends a deletion version. A repeat of
an already deleted record returns unchanged when expectedVersion is at most
the current version.
Restore with
POST /v1/projects/{projectId}/attachments/{attachmentId}/restore, sending
version for the saved state to copy and expectedVersion for the current
head, including its deletion version. Restore appends a new version and clears
deletion; it never rewrites a historical version. Its receipt names the new
version and restoredFrom. An already current and live state returns
unchanged when expectedVersion is at most the current version.
A deleted folder or a clip in Story’s Trash hides its attachments. Restoring
the parent brings those records and their history back. Restore the parent
before writing to its attachments.
The endpoint reference describes each
request and response. These routes access text on a Story clip; they do not
provide Story clip or timeline editing endpoints.