API

The REST API lets your own scripts and tools read and change your library. The browser extension uses it too.

Authenticate

Generate a token in Settings → API token and send it with every request:

curl -H "Authorization: Bearer lec_…" https://lectern.segredo.dev/api/v1/me

Each account has one active token; generating a new one stops the old one working.

Endpoints

Every endpoint, with its parameters and responses, is described in openapi.yaml.

Request Does
GET /api/v1/me Your account and rate limit
GET /api/v1/items Lists items: status, favorite, tag, content_type, updated_since, order, limit, cursor
POST /api/v1/items Saves a url, optionally with the page's html, tags and status
GET /api/v1/items/:id An item; include=markdown,annotations adds its text and highlights
PATCH /api/v1/items/:id Changes status, favorite, reading_progress, position or note
DELETE /api/v1/items/:id Deletes an item
GET /api/v1/search?q= Searches, best matches first
GET, POST /api/v1/items/:id/annotations An item's highlights, or a new one
PATCH, DELETE /api/v1/annotations/:id Changes or deletes a highlight
GET /api/v1/tags Tags with their counts
PATCH, DELETE /api/v1/tags/:id Renames (or merges) or deletes a tag
POST, DELETE /api/v1/items/:id/tags Tags or untags an item

Saving a URL that's already in your library answers 200 with the existing item; a new one answers 201.

Paging

Lists return next_cursor. Pass it back as cursor until it's null. To keep a copy in sync, ask for order=updated&updated_since= the time of your last sync.

Errors and limits

Errors always look like {"error": {"code": "invalid", "message": "…", "field": "url"}}.

Each token may make 120 requests a minute. Every response says where you stand in X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 adds Retry-After, in seconds.

Lectern · read later, here or on your own server