search for standard sites pub-search.waow.tech
search zig blog atproto

API reference#

base URL: https://leaflet-search-backend.fly.dev

endpoints#

GET /search?q=<query>&tag=<tag>&platform=<platform>&since=<date>&author=<did|handle>&mode=<mode>

full-text search across documents and publications.

parameters:

param type required description
q string no* search query (titles and content)
tag string no filter by tag (documents only)
platform string no filter by platform: leaflet, pckt, offprint, greengale, whitewind, other
since string no ISO date, filter to documents created after
author string no filter by author: DID (did:plc:xyz) or handle (nate.bsky.social). handles are resolved server-side via AT Protocol.
mode string no keyword (default), semantic, or hybrid. semantic uses voyage-4-lite embeddings + turbopuffer ANN. hybrid merges keyword + semantic via reciprocal rank fusion.
format string no v2 wraps response in {"results": [...], "total": N, "hasMore": bool}
limit int no max results to return (default 20)
offset int no pagination offset

*at least one of q, tag, or author required

filter behavior by mode:

  • keyword: respects all filters (tag, platform, since, author)
  • semantic: respects platform and author. ignores tag and since.
  • hybrid: keyword half respects all filters, semantic half respects platform and author. results merged via RRF.

response:

[
  {
    "type": "article|looseleaf|publication",
    "uri": "at://did:plc:.../collection/rkey",
    "did": "did:plc:...",
    "title": "document title",
    "snippet": "...matched text...",
    "createdAt": "2025-01-15T...",
    "rkey": "abc123",
    "basePath": "gyst.leaflet.pub",
    "platform": "leaflet",
    "path": "/001",
    "coverImage": "",
    "handle": "@user.bsky.social"
  }
]

with format=v2:

{
  "results": [ /* same as above */ ],
  "total": 89,
  "hasMore": false
}

hybrid mode adds source and score fields:

{
  "source": "keyword+semantic",
  "score": 0.85
}

result types:

  • article: document in a publication
  • looseleaf: standalone document (no publication)
  • publication: the publication itself (only returned for text queries, not tag/platform filters)

ranking: hybrid BM25 + recency. text relevance primary, recent docs boosted (~1 point per 30 days).

similar#

GET /similar?uri=<at-uri>

find semantically similar documents using vector similarity (voyage-4-lite embeddings + turbopuffer ANN).

parameters:

param type required description
uri string yes AT-URI of source document

response: same format as search (array of results)

tags#

GET /tags

list all tags with document counts, sorted by popularity.

response:

[
  {"tag": "programming", "count": 42},
  {"tag": "rust", "count": 15}
]
GET /popular

popular search queries.

response:

[
  {"query": "rust async", "count": 12},
  {"query": "leaflet", "count": 8}
]

stats#

GET /stats

index statistics and request timing.

response:

{
  "documents": 11445,
  "publications": 2603,
  "embeddings": 10900,
  "searches": 5000,
  "errors": 5,
  "cache_hits": 1200,
  "cache_misses": 800,
  "timing": {
    "search_keyword": {"count": 1000, "avg_ms": 25, "p50_ms": 20, "p95_ms": 50, "p99_ms": 80, "max_ms": 150},
    "search_semantic": {"count": 100, "avg_ms": 350, "p50_ms": 340, ...},
    "search_hybrid": {"count": 50, "avg_ms": 380, ...},
    "similar": {"count": 200, "avg_ms": 150, ...},
    "tags": {"count": 500, "avg_ms": 5, ...},
    "popular": {"count": 300, "avg_ms": 3, ...}
  }
}

activity#

GET /activity

hourly activity counts (last 24 hours).

response:

[12, 8, 5, 3, 2, 1, 0, 0, 1, 5, 15, 25, 30, 28, 22, 18, 20, 25, 30, 35, 28, 20, 15, 10]

dashboard#

GET /api/dashboard

rich dashboard data for analytics UI. includes platform counts (no separate /platforms endpoint).

response:

{
  "startedAt": 1705000000,
  "searches": 5000,
  "publications": 2603,
  "documents": 11445,
  "platforms": [{"platform": "leaflet", "count": 5399}],
  "tags": [{"tag": "programming", "count": 42}],
  "timeline": [{"date": "2025-01-15", "count": 25}],
  "topPubs": [{"name": "gyst", "basePath": "gyst.leaflet.pub", "count": 150}],
  "timing": {...}
}

health#

GET /health

response:

{"status": "ok"}

building URLs#

documents can be accessed on the web via their basePath and platform-specific patterns:

platform URL pattern example
leaflet https://{basePath}/{rkey} https://gyst.leaflet.pub/3ldasifz7bs2l
pckt https://{basePath}{path} https://devlog.pckt.blog/some-slug
offprint https://{basePath}{path} https://dalisay.offprint.app/a/3me5ucj7vxf23-title-slug
greengale https://{basePath}{path} https://3fz.greengale.app/001
whitewind https://whtwnd.com/{did}/{rkey} https://whtwnd.com/did:plc:.../3abc123
publications https://{basePath} https://gyst.leaflet.pub