Skip to content

API reference

Read and add to your library from scripts, MCP clients and other tools. Version 1. Machine-readable: /v1/openapi.json.

Authentication

Create a personal access token in Settings → API tokens and send it as a bearer token. Read-only tokens can list and search; read-and-write tokens can also save and organise. 120 requests a minute per token; responses carry RateLimit-Remaining.

curl https://refna.app/v1/refs?q=palette \
  -H "Authorization: Bearer refna_pat_…"

Save links from a run

# 1. find a run and its links
curl https://refna.app/v1/runs -H "Authorization: Bearer $REFNA_TOKEN"
curl "https://refna.app/v1/runs/RUN_ID/links?limit=200" -H "Authorization: Bearer $REFNA_TOKEN"

# 2. save some of them, straight into a collection
curl -X POST https://refna.app/v1/refs \
  -H "Authorization: Bearer $REFNA_TOKEN" -H "Content-Type: application/json" \
  -d '{"runId":"RUN_ID","linkIds":["LINK_ID"],"collectionId":"COLLECTION_ID"}'

Use with Claude (MCP)

The Refna MCP server lets Claude and other MCP clients search and organise your library with your token. Add it to your client’s MCP configuration:

{
  "mcpServers": {
    "refna": {
      "command": "node",
      "args": ["/path/to/refna/packages/mcp/dist/index.js"],
      "env": { "REFNA_TOKEN": "refna_pat_…" }
    }
  }
}

Endpoints

GET/v1/me— Check the connection

Who the token acts as, and the plan's library allowance.

Scope: library:read

GET/v1/refs— List or search references

Newest first; collection order with collectionId; relevance order with q (every word must match, as a prefix).

Scope: library:read

Parameters for GET /v1/refs
qSearch notes, tags, titles, summaries and where links were found
tagOnly references with this tag
collectionIdOnly references in this collection, in its order
archivedtrue lists archived references instead
cursornextCursor from the previous page
limit1–100

POST/v1/refs— Save links from a run

One reference per URL: saving a URL again adds the new run's evidence. Up to 500 links per call.

Scope: library:write

Body — Links of one of your runs, and optionally a collection to add them to

{
  "runId": "3f6c1d2e-8a4b-4c7d-9e1f-2a3b4c5d6e7f",
  "linkIds": [
    "3f6c1d2e-8a4b-4c7d-9e1f-2a3b4c5d6e7f"
  ],
  "collectionId": "3f6c1d2e-8a4b-4c7d-9e1f-2a3b4c5d6e7f"
}

GET/v1/refs/lookup— Look up a page address

Whether a page is in the library. The address is normalised (fragment and tracking parameters dropped) before matching. Returns { ref: null } when it isn't saved.

Scope: library:read

Parameters for GET /v1/refs/lookup
urlFull http(s) address

GET/v1/refs/{id}— Get a reference

Scope: library:read

Parameters for GET /v1/refs/{id}
idUUID

PATCH/v1/refs/{id}— Edit a note or tags

Only the annotation layer is writable; evidence and observation never change.

Scope: library:write

Parameters for PATCH /v1/refs/{id}
idUUID

Body — note (null clears it) and/or tags (replaces them)

{
  "note": "Use for wireframes",
  "tags": [
    "design",
    "tools"
  ]
}

GET/v1/collections— List collections

Scope: library:read

POST/v1/collections— Create a collection

Scope: library:write

Body — title (1–120) and optional description

{
  "title": "Design",
  "description": null
}

GET/v1/collections/{id}— Get a collection with its references

The versioned CollectionExport document (schemaVersion 1.0.0), references in collection order.

Scope: library:read

Parameters for GET /v1/collections/{id}
idUUID

POST/v1/collections/{id}/items— Add references to a collection

Appends in the order given; references already in it are skipped.

Scope: library:write

Parameters for POST /v1/collections/{id}/items
idUUID

Body — Up to 500 reference ids

{
  "refIds": [
    "3f6c1d2e-8a4b-4c7d-9e1f-2a3b4c5d6e7f"
  ]
}

GET/v1/runs— List your recent runs

Scope: library:read

Discovery order. Use the ids with POST /v1/refs.

Scope: library:read

Parameters for GET /v1/runs/{id}/links
idUUID
afterLast position seen (start at -1)
limit1–500

GET/v1/watches— List watched pages

Pages Refna re-checks on a schedule, with the last check and the last check that found changes.

Scope: library:read

Parameters for GET /v1/watches
archivedtrue lists archived watches instead

POST/v1/watches— Watch a page

Checks list the page's links (no descriptions) and don't use the monthly run allowance; the plan's watch limit and schedules are the budget. Watching the same page again returns the existing watch (200). Free: 2 watches, weekly. Pro: 25, daily or weekly.

Scope: library:write

Body — url, mode (page | site), cadence (daily | weekly)

{
  "url": "https://tools.example/",
  "mode": "page",
  "cadence": "weekly"
}

GET/v1/watches/{id}— Get a watch and its recent checks

Scope: library:read

Parameters for GET /v1/watches/{id}
idUUID

PATCH/v1/watches/{id}— Change, pause, archive or check now

checkNow runs a check at the next scheduler tick (within about a minute), at most once an hour.

Scope: library:write

Parameters for PATCH /v1/watches/{id}
idUUID

Body — Any of cadence, paused, archived, checkNow

{
  "paused": true
}

GET/v1/watches/{id}/changes— What changed

Links added and removed in one check — by default the latest check that found changes. removalsChecked is false when discovery was cut short; then only additions are reported. Up to 1000 per kind; counts on the check are exact.

Scope: library:read

Parameters for GET /v1/watches/{id}/changes
idUUID
checkA check id from GET /v1/watches/{id}
kindadded or removed

Errors

Every error is { "error": { "code", "message" } }.

Error codes
400invalid_requestThe body or query didn't validate; the message names the field.
401missing_token / invalid_tokenNo token, or it's malformed, revoked or expired.
402allowance_usedSaving would go over the plan's library allowance.
403insufficient_scope / watch_limit / cadence_not_in_planThe token lacks the scope this endpoint needs; or (watches) the plan's active-watch limit or a schedule it doesn't include.
404not_foundIt doesn't exist, or isn't yours.
409too_many_tokens(Token creation) 20 active tokens per account.
429rate_limited / too_soon120 requests a minute per token; see Retry-After. too_soon: a watch was checked in the last hour.