Skip to main content

Bookmark query syntax

The /api/v1/bookmarks endpoint supports a flexible, JSON-style query language that mirrors what the dashboard uses. This guide explains every knob you can turn so you can build reliable automations without guessing.

Bookmark IDs

id in bookmark API responses is a public UUID string (for example, 5cb58dd5-40f3-4df4-9218-7f3fb53e9ec3). Use this value for bookmark routes like /api/v1/bookmarks/{id}/ and /api/v2/bookmarks/{id}/notes/. The internal incremental database id is not exposed via the API.

Pagination

  • limit — number of rows per page. Must be an integer between 1 and 100 (default 50).
  • page — 1-based page index (minimum 1, default 1).

Example: GET /api/v1/bookmarks?limit=25&page=2

Use the search parameter to perform a case-insensitive match across title, link, author, and notes.

/api/v1/bookmarks?search=machine%20learning

Filtering syntax

Filters use bracket notation inspired by Node/Express query parsers.

filter[field][operator]=value
filter[_or][0][field][operator]=value
filter[_and][1][field][operator]=value

Supported operators:

OperatorMeaningExample
_eqequalsfilter[read][_eq]=false
_neqnot equalsfilter[source_type][_neq]=rss
_containscase-insensitive substringfilter[title][_contains]=queso
_ncontainsdoes not containfilter[notes][_ncontains]=TODO
_nullis nullfilter[source_id][_null]=true
_nnullis not nullfilter[source_id][_nnull]=true
_emptyempty string or nullfilter[meta_image][_empty]=true
_nemptynot emptyfilter[meta_image][_nempty]=true
_gtgreater thanfilter[estimated_time][_gt]=10
_gtegreater or equalfilter[estimated_time][_gte]=5
_ltless thanfilter[estimated_time][_lt]=60
_lteless or equalfilter[estimated_time][_lte]=30

Logical groups let you combine clauses:

filter[_or][0][read][_eq]=false
filter[_or][1][tags][_contains]=design

Sorting

Pass sort=<field> to order results. Prefix with - for descending (sort=-published_date).

Allowed fields: date_created, date_updated, published_date, estimated_time.

Unsupported fields return 400 Bad Request so you know immediately something is wrong.

Field selection

Use fields[]=field_name (repeatable) to trim the payload to specific attributes. All field names from the list below are supported:

id, date_created, date_updated, title, link, author, estimated_time, is_quote, is_til, tags, read, notes, snapshot, has_snapshot, meta_image, published_date, source_type, source_id.

Example: /api/v1/bookmarks?fields[]=id&fields[]=tags returns only the bookmark IDs and tag arrays. When requesting exactly id + tags, you may bump limit up to 1000 for bulk tag syncs.

Meta counters

Include meta=total_count and/or meta=filter_count to request extra metadata alongside data.

/api/v1/bookmarks?meta=total_count&meta=filter_count

Without explicit meta params the response defaults to total count (post-filter when filters/search are present, otherwise full count).

Aggregations

Set a single aggregate[function]=field argument to compute metrics instead of returning rows.

Supported combinations:

  • count — fields: id, read, source_type, estimated_time
  • countDistinct — same fields as count
  • sum, avg, min, max — field: estimated_time

Example (count unread bookmarks):

/api/v1/bookmarks?filter[read][_eq]=false&aggregate[count]=id

Aggregations respect search and filter clauses. Invalid fields or functions return 400 Bad Request.

Putting it together

Combined example that surfaces unread design articles saved this month, newest first:

/api/v1/bookmarks?
limit=25&
sort=-published_date&
filter[_and][0][read][_eq]=false&
filter[_and][1][tags][_contains]=design&
filter[_and][2][published_date][_gte]=2024-05-01

You can always test queries in the dashboard first, capture the network request, and reuse the query string in your automation.