API reference

Batata exposes a small REST API for everything the web app does. There are also Pinboard-compatible endpoints so existing Pinboard clients work out-of-the-box.

Authentication

The API supports two auth modes:

1. Personal Access Tokens (PATs)

Generate a PAT in Settings → API Tokens. Then pass it as a query parameter — same convention Pinboard uses:

curl 'https://batata.page/api/v1/posts/recent?auth_token=YOUR_TOKEN'

2. Session cookie (for browser-based scripts)

If you're signed in to batata.page, your session cookie works automatically. This is what the web app, Chrome extension, and bookmarklet use.

Base URL

https://batata.page/api

Bookmarks

POST /bookmarks

Create a bookmark. Triggers inline archive + embed + enrich.

POST /bookmarks
content-type: application/json

{
  "url": "https://example.com",
  "title": "Optional title",
  "description": "Optional notes",
  "tags": ["tag1", "tag2"],
  "is_private": true
}

Returns 201 with the created bookmark. 409 if you've already saved this URL. 403if you're a free user at the 100-bookmark cap.

GET /bookmarks

List the current user's bookmarks. Newest first.

GET /bookmarks?limit=50&offset=0&tag=startups&q=negotiation
  • limit (1-200, default 50) — page size
  • offset — pagination offset
  • tag (optional) — filter to a specific tag
  • q (optional) — full-text search on title + description + URL

GET /bookmarks/{id}/archive

Get the archived text + signed URL to the full HTML snapshot (if R2 is configured).

DELETE /bookmarks/{id}

Delete a bookmark. Returns 204.

Search

GET /search

Hybrid search: combines BM25 keyword scoring with pgvector cosine similarity using Reciprocal Rank Fusion.

GET /search?q=negotiation&mode=hybrid
  • modehybrid (default), keyword, or semantic

Ask

POST /ask

RAG: embeds the question, retrieves top chunks, synthesizes a grounded answer with citations.

POST /ask
content-type: application/json

{ "question": "What have I saved about productivity?" }

Returns the answer text and an array of cited sources (only sources actually referenced).

Tags

GET /tags

List all tags with usage counts, sorted by frequency.

Import

POST /import/pinboard

Upload a Pinboard JSON export as multipart form data with field name file. Free-tier accounts cap at 100 bookmarks; over-cap imports return limit_reached: true in the response.

Pinboard compatibility

Existing Pinboard clients (Pinner, Pushpin, etc.) work by pointing them at https://batata.page/api with a Batata PAT in place of the Pinboard token.

  • GET /v1/posts/all — all bookmarks, Pinboard JSON format
  • GET /v1/posts/recent — most recent bookmarks (default count=15)

Both support ?tag= filtering and the standard ?auth_token= query auth.

Rate limits

We don't hard rate-limit Pro accounts beyond OpenAI's upstream limits for Ask and Search. The contact form is rate-limited to 3 requests per IP per hour. Magic-link requests are limited to 5 per email per 15 min.

Errors

  • 401 — not authenticated
  • 403 — free tier limit reached (on save)
  • 404 — resource not found
  • 409 — duplicate URL
  • 429 — rate limited