# Move a Readwise Reader library to Sponge

List every saved document with the Reader API, then save each link to Sponge with a short script and re-create the highlights that still match.

By Hraness · Published 2026-09-26

Drafted with AI from the source code and reviewed by Claude Opus 5.5 (claude-opus-5-5) editorial review.

There is no one-click Reader importer in Sponge. The move is a scripted loop over the Reader API: page through your documents, save each link through Sponge’s library command, then re-create the highlights and notes that still match the saved copy. Every step below uses documented public endpoints on both sides.

## Get tokens for both services

1. Get your Reader access token at [readwise.io/access_token](https://readwise.io/access_token).
2. Sign in to Sponge, open `/settings/api`, and create a token with `library:write`. Add `library:read` if you want the same credential to check results. Keep the token in `SPONGE_API_TOKEN` and never print it. Every response’s `X-Sponge-Requests-Remaining` header shows what is left of the token’s request budget.
3. Set up a working directory for the export, with one JSON file per list page and a log of what your loop has already saved.

## Export your Reader documents

`GET https://readwise.io/api/v3/list/` returns your library in pages. Pass `Authorization: Token <your token>`, follow `nextPageCursor` until it is null, and keep each result’s `id`, `source_url`, `category`, `location`, and `notes`. The endpoint allows 20 requests per minute; on a `429`, wait out the `Retry-After` header.

- Limit the loop to the categories Sponge can keep: `article`, `pdf`, and web pages saved as other types. EPUBs, tweets, videos, emails, and RSS items have no Sponge equivalent.
- If you uploaded files, add `withRawSourceUrl` to list calls. Each result then includes a direct link to the stored file that expires after one hour, so download those files as you go.
- Reader stores highlights and notes as documents too. Entries with `category=highlight` carry `parent_id` (the article they belong to), `content` (the passage), and `notes` (your note). List them now and save the JSON.

## Save each link to Sponge

For every exported `source_url`, send Sponge’s `save-link` command once. Give each save a stable `idempotencyKey` of 16 or more characters, such as `readwise-<document id>`, so a retried request returns the same item instead of a duplicate.

```sh
curl -X POST https://sponge.computer/api/v1/library \
  -H "Authorization: Bearer $SPONGE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"save-link","url":"https://example.org/field-study","idempotencyKey":"readwise-01abc123"}'
```

The command stores the save immediately and prepares the capture in the background. Read the item back with `list` or `get` to see when its copy is ready. If a page cannot be fetched, Sponge keeps the item and marks the capture as failed or partial. An agent running the Sponge CLI can do the same through the `sponge_library_save_link` MCP tool with a `requestKey` per save.

> Sponge fetches the page when you save it; it does not copy Reader’s stored version. A page that changed since Reader saved it arrives as it is now, and a page that needs a sign-in does not come over at all.

## Re-create your highlights and notes

A Sponge highlight anchors to the saved copy’s text: each selection carries the passage, its start and end offsets, and the context on each side. To carry a Reader highlight over:

1. Read the saved item’s text with the `reader-page` command, which returns the capture and representation identifiers a selection needs.
2. Find the Reader highlight’s `content` in that text and build the selection: `exact` holds the passage, `start` and `end` its offsets, `prefix` and `suffix` the context on each side, plus the capture, representation, and block identifiers from step one.
3. Send `{"type":"highlight","sourceId":…,"selections":[…],"idempotencyKey":…}` with a stable key per highlight. Sponge refuses a selection that does not match the saved text.

If Reader’s stored page differs from what Sponge captured, some passages will not be found; those highlights stay in your export as records rather than anchored marks. A Reader note that is not a highlight becomes a `create-note` item on the same source.

## Carry over reading state, files, and tags

- Reader’s `archive` location becomes Sponge’s archived state and `seen` becomes read: send `set-reading-state` with the item’s current `expectedRevision` plus `read` and `archived`.
- `shortlist` and `feed` have no Sponge equivalent; decide for yourself whether to file those items as unread or archived.
- Tags do not transfer, because Sponge has no tags. It keeps sources, highlights, and notes.
- Downloaded PDFs and saved HTML files can be uploaded through Sponge’s file upload (`prepare-upload`, then `finish-upload`); EPUBs are not a supported file type.
- Sponge’s API has an import command, `prepare-import`, but it works only with a migration plan Sponge has set up for you, so you cannot use it on your own today. Use the loop above instead.

## Rerun the loop to finish failed saves

Keep the Reader export and your run log together, with a record of which document IDs saved, which are waiting on capture, and which failed. Then run the same loop again with the same keys. Finished saves return the same items, so only the missing or failed entries move.

## Sources

- [Readwise Reader API](https://readwise.io/reader_api), checked 2026-09-26
- [Sponge agent research skill](https://sponge.computer/skills/sponge-research/SKILL.md), checked 2026-09-26
- [Sponge OpenAPI document](https://sponge.computer/openapi.json), checked 2026-09-26
