Items
A saved page, file, or supplied text. Addressed by a UUID.
Objects
Items, notes, and highlights under one search. Addressed by a stable
ref.Assets
The original bytes of an uploaded file, streamed back on demand.
Save something
POST /v1/library/items takes either a url for smry to fetch, or title plus
content you supply yourself.
item, an extraction report, and alreadySaved. Saving
the same url again returns the existing item with alreadySaved: true rather
than creating a duplicate, which is what makes a retry after a timeout safe.
externalId lets you carry your own identifier through — see
Retries and idempotency.
Uploading a file
Two steps, in this order:1
Admit the file
POST /v1/library/items with title and fileName — no bytes. Both are
required; mimeType and format are optional. You get back an item id.2
Send the bytes
PUT /v1/library/items/{id}/asset with the binary body, its Content-Type,
and an X-Smry-File-Name header. The global ceiling is 100 MB, and audio
gets all of it — but anything smry parses for text, a PDF or an EPUB
included, is capped at 25 MB, so a 40 MB PDF is a 413. smry reads the
extension from X-Smry-File-Name to pick the cap. Concurrent replacements
of the same item are serialized, so a second write while one is in flight
returns 409.GET /v1/library/items/{id}/asset, which streams the
original with its stored MIME type and supports a single HTTP byte range — use
it for audio, video, and large documents.
Find things
Two operations, two jobs.Search everything
ref. Pass it to GET /v1/library/objects/{ref}
to read the full object, whatever type it turned out to be.
GET /v1/library/items filters on query, tag, status, starred,
contentKind, captureMethod, format, externalId, savedAfter, and
updatedAfter.
Reading history lives behind
view=history. It is the only way to get it.
GET /v1/library/items?view=history returns what the account has read, in
reading order, rather than what it has saved.savedAfter and updatedAfter are not interchangeable: savedAfter filters on
when the item entered the library, updatedAfter on when it last changed. Use
updatedAfter for polling, savedAfter for backfill.
Read one item
GET /v1/library/items/{id}/contentreturns a bounded window plusnextCursor, the same way article reading works.POST /v1/library/items/{id}/searchreturns only the passages inside that one item that match a query, each with ananchor.
Change things
PATCH /v1/library/items/{id} moves, tags, stars, reclassifies, or marks an
item read:
tags is a complete replacement, not a merge. Read the item’s current tags
first if you mean to add one.
PATCH /v1/library/items (no id) applies one set of changes to up to 100
ids at once, and reports back updated and missing.
DELETE /v1/library/items/{id} removes the item. Uploaded file bytes are
permanently deleted from synced storage; notes and highlights are kept.
Sync into your own store
GET /v1/library/changes is the incremental feed of every mutation and
deletion. The first call is the part people get wrong:
1
Take a checkpoint first
GET /v1/library/changes?cursor=latest. Keep the nextCursor it returns.2
Then list the current library
Page
GET /v1/library/items to load the state as it is now.3
Then poll from the checkpoint
Continue from the stored
nextCursor. Anything that changed during step 2
arrives as a change event, so nothing is lost and nothing is duplicated.Python
GET /v1/library/counts gives the totals by status and content kind without
paging anything — useful for a progress bar or a sanity check after a sync.
Next
Cursors and paging
Library cursors are
nextCursor; feed cursors are next_cursor. Don’t mix
them.Follow sources
Get new material into the library without asking for it.