Acorny

API Reference

Acorny API docs for Readwise-compatible imports and Obsidian export sync.

Build with the Acorny API: create highlights through Readwise-compatible endpoints and sync highlights to Obsidian, backup scripts, or local-first clients with the export feed.

Two supported write APIs

Acorny native

Use POST /api/v1/ingest/highlights when you control the client. The native contract accepts structured source metadata, tags, notes, highlight URLs, client references, and an idempotency key so retries can be safe.

This is the best fit for scripts, CLI tools, custom readers, or migration jobs that can shape payloads specifically for Acorny.

Readwise-compatible

Use POST /api/v2/highlights/ when a client already speaks the Readwise highlight format. Moon+ Reader and similar clients can point at Acorny with an Acorny token instead of a Readwise token.

The compatibility endpoint is intentionally familiar: send an array of highlights with text, title, author, source URL, location, note, and timestamp fields.

Authentication

API access uses Personal Access Tokens created in your Acorny account settings. Open Settings and create an import API token for write APIs, or create a token under Obsidian / Export tokens for the read-only export feed. Give each token a descriptive name such as Moon+ Reader, Import Script, or Obsidian, and copy the plain token immediately. The token is shown only once; the server stores only a hash.

Both authorization styles are accepted: Authorization: Token YOUR_TOKEN for Readwise-style clients and Authorization: Bearer YOUR_TOKEN for generic HTTP clients. To verify an import token, call GET /api/v2/auth/. A valid token returns 204 No Content, while missing or invalid credentials return 401.

Request shape

The native endpoint expects an items array. Each item includes a required highlight body in quote, a required structured source object with type and title, and optional fields such as note, tags, highlightedAt, highlightUrl, and clientRef. Add an Idempotency-Key header for safe retries.

POST /api/v1/ingest/highlights
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
Idempotency-Key: 8f1f3b2a-4f10-4d4d-bf8c-1aa6c8a6e2f1

{
  "items": [
    {
      "quote": "Call me Ishmael.",
      "note": "Opening line",
      "tags": ["literature"],
      "highlightedAt": "2020-07-14T20:11:24+00:00",
      "source": {
        "type": "document",
        "title": "Moby Dick",
        "author": "Herman Melville"
      },
      "highlightUrl": "https://example.com/moby-dick#h=1",
      "clientRef": "my-app:42"
    }
  ]
}

Compatibility fields

The Readwise-compatible endpoint accepts highlights[].text as the required body. Title, author, source_url, highlighted_at, location, location_type, note, category, source_type, image_url, and highlight_url are accepted for compatibility. Acorny applies Readwise-style deduplication using title, author, text, and source_url so repeated imports do not create duplicate rows.

A successful Readwise-compatible request returns a Readwise-style book array. A successful native request returns an ingest summary with accepted, created, skipped, restored, updated, failed, and errors fields. This gives scripts enough information to log what happened without fetching the whole library again.

Read highlights with the export feed

Use GET /api/v1/exports/highlights/feed for read-only highlight sync. This cursor-paginated feed is built for Obsidian sync, backup scripts, and local-first clients that need stable highlight ids, source metadata, and incremental polling without requiring a full database export on every run.

Use cases

  • Obsidian sync for local Markdown vaults and spaced-repetition workflows
  • backup scripts that archive highlights outside Acorny
  • local-first clients that need stable ids, source metadata, and incremental polling

Create a token under Obsidian / Export tokens in Settings, then call the feed with Authorization: Token YOUR_EXPORT_TOKEN. The optional limit query defaults to 100 and is clamped at 500. Send the opaque cursor from the previous response back unchanged to continue a sync.

GET /api/v1/exports/highlights/feed?limit=100
Authorization: Token YOUR_EXPORT_TOKEN

{
  "highlights": [
    {
      "id": "hl_123",
      "quote": "Call me Ishmael.",
      "quoteMarkdown": null,
      "note": "Opening line",
      "tags": ["literature"],
      "updatedAt": "2026-06-22T09:00:00.000Z",
      "source": {
        "id": "src_123",
        "title": "Moby Dick",
        "author": "Herman Melville",
        "canonicalUrl": "https://example.com/moby-dick",
        "type": "document"
      }
    }
  ],
  "nextCursor": "eyJtb2RlIjoicmVhZHkiLCJ3YXRlcm1hcmsiOiIyMDI2...",
  "done": true
}

Continue calling the endpoint with cursor=nextCursor until done is true. Save the final nextCursor for the next sync run. The feed intentionally overlaps a short safety window, so clients should upsert by highlight.id.

Rate limits

The Readwise-compatible API allows 60 requests per minute per token. The native endpoint uses the standard authenticated import-token limit, and the export feed uses the standard authenticated export-token limit. If a client exceeds the limit, Acorny returns 429 Too Many Requests with a Retry-After header. Clients should wait for that duration and retry with exponential backoff.

Error handling

Use 400 responses to fix invalid payloads, 401 for missing or revoked tokens, 413 for oversized batches, 409 when an idempotency key is reused with a changed payload, 422 when all rows fail validation, and 5xx responses for server-side retry paths.

Integration practices

Send highlights in batches of up to 100 items. Smaller batches are easier to retry and easier to inspect in logs, while still keeping imports fast enough for most personal libraries. Store the upstream item identifier in clientRef when you have one, because it helps connect import logs back to the source application.

Use one Personal Access Token per external client or automation. Separate tokens make rotation safer: if a laptop, script, or reading app is retired, revoke only that token instead of changing every integration. Never put a token in a public repository, client-side web bundle, shared screenshot, or browser extension source that other users will install.

For idempotent retries, generate one idempotency key for a request and reuse it only when retrying the exact same payload. If you edit the payload, generate a new key. This keeps timeout recovery predictable and prevents accidental duplicates during unreliable network conditions.

Self-hosted users should replace the public API host with their own Acorny instance URL in every example. Keep the path structure the same unless your deployment intentionally rewrites API routes.

When building a long-running importer, log the request status, accepted count, created count, skipped count, and failed count for each batch. These values make it much easier to resume a partial import without guessing which source rows already reached Acorny.

Coming soon

The API currently covers highlight creation and a read-only export feed. Mutation APIs, webhooks for review events, and an OpenAPI or Swagger specification are still on the roadmap. If your integration needs one of those surfaces now, contact Acorny with the use case so it can be prioritized against real workflows.