Comprehensive Python SDK for Readwise with high-level workflow abstractions. Supports both the Readwise API (v2) for highlights/books and the Reader API (v3) for documents.
- Features
- Installation
- Quick Start
- Architecture
- Core API Usage
- Managers
- Workflows
- Contrib Interfaces
- CLI
- Development
- Contributing
- License
- V2 API (Readwise): Full support for highlights, books, tags, and daily review
- V3 API (Reader): Full support for documents, inbox, reading list, and archive
- Managers: High-level abstractions for common operations
- Workflows: Pre-built workflows for digests, tagging, and syncing
- Contrib: Convenience interfaces for common integration patterns
- CLI: Command-line interface for quick operations
pip install readwise-plusWith CLI support:
pip install readwise-plus[cli]from readwise_sdk import ReadwiseClient
# Initialize with your API token
client = ReadwiseClient(api_key="your_token_here")
# Or use environment variable READWISE_API_KEY
client = ReadwiseClient()
# Validate your token
client.validate_token()
# Get all highlights
for highlight in client.v2.highlights.list():
print(highlight.text)
# Get Reader inbox
for doc in client.v3.documents.list(location="new"):
print(doc.title)The SDK is organized into layers of increasing abstraction:
readwise-plus/
├── Core Layer
│ ├── V2 Client → client.v2.* (Readwise API)
│ └── V3 Client → client.v3.* (Reader API)
├── Manager Layer
│ ├── HighlightManager → Highlight operations
│ ├── BookManager → Book operations
│ ├── DocumentManager → Document operations
│ └── SyncManager → Sync state tracking
├── Workflow Layer
│ ├── DigestBuilder → Create highlight digests
│ ├── ReadingInbox → Inbox management
│ ├── TagWorkflow → Auto-tagging
│ └── BackgroundPoller → Background sync
└── Contrib Layer
├── HighlightPusher → Push highlights to Readwise
├── DocumentImporter → Import documents to Reader
└── BatchSync → Batch synchronization
from readwise_sdk import ReadwiseClient
from datetime import datetime
client = ReadwiseClient()
# List highlights with filtering
highlights = client.v2.highlights.list(
book_id=123,
updated_after=datetime(2024, 1, 1),
)
# Get a specific highlight
highlight = client.v2.highlights.get(highlight_id=456)
# Create a highlight
new_highlight = client.v2.highlights.create(
text="Important quote from the book",
title="Book Title",
author="Author Name",
source_type="book",
)
# Export all highlights with full book metadata
for book in client.v2.export_highlights():
print(f"{book.title}: {len(book.highlights)} highlights")
for h in book.highlights:
print(f" - {h.text[:50]}...")
# Get daily review highlights
review = client.v2.get_daily_review()
for highlight in review.highlights:
print(highlight.text)# List inbox documents
for doc in client.v3.documents.list(location="new"):
print(f"{doc.title} ({doc.category})")
# Save a URL to Reader
result = client.v3.save_url("https://example.com/article")
print(f"Saved: {result.id}")
# Get document with full content
doc = client.v3.documents.get(doc_id, with_html=True)
print(doc.html)
# Move document to archive
client.v3.documents.update(doc_id, location="archive")
# Filter by category
articles = client.v3.documents.list(category="article")
pdfs = client.v3.documents.list(category="pdf")Managers provide higher-level operations with better ergonomics.
from readwise_sdk.managers import HighlightManager
highlights = HighlightManager(client)
# Get recent highlights
recent = highlights.get_highlights_since(days=7)
# Search highlights
results = highlights.search("python programming")
# Bulk operations
highlights.bulk_tag(highlight_ids, "to-review")
highlights.bulk_delete(highlight_ids)
# Get highlights by book
book_highlights = highlights.get_by_book(book_id=123)from readwise_sdk.managers import BookManager
books = BookManager(client)
# List all books
all_books = books.list()
# Get books by category
articles = books.get_by_category("articles")
# Get book with highlights
book = books.get_with_highlights(book_id=123)from readwise_sdk.managers import DocumentManager
docs = DocumentManager(client)
# Get inbox
inbox = docs.get_inbox()
# Archive a document
docs.archive(doc_id)
# Get reading stats
stats = docs.get_stats()
print(f"Inbox: {stats.inbox_count}, Archive: {stats.archive_count}")Pre-built workflows for common use cases.
from readwise_sdk.workflows import DigestBuilder
digest = DigestBuilder(client)
# Daily digest
daily = digest.build_daily()
print(daily.to_markdown())
# Weekly digest
weekly = digest.build_weekly()
# Book-specific digest
book_digest = digest.build_for_book(book_id=123)
book_digest.save("book-notes.md")from readwise_sdk.workflows.tags import TagWorkflow, TagPattern
workflow = TagWorkflow(client)
# Define tagging patterns
patterns = [
TagPattern(r"\bpython\b", "python", case_sensitive=False),
TagPattern(r"\bmachine learning\b", "ml", case_sensitive=False),
TagPattern(r"TODO:", "actionable", search_in_notes=True),
]
# Auto-tag highlights
result = workflow.auto_tag_highlights(patterns, dry_run=True)
print(f"Would tag {result.matched_count} highlights")
# Apply tags
result = workflow.auto_tag_highlights(patterns, dry_run=False)
# Rename a tag
workflow.rename_tag(old_name="todo", new_name="actionable")from readwise_sdk.workflows import ReadingInbox
inbox = ReadingInbox(client)
# Get prioritized inbox
prioritized = inbox.get_prioritized(limit=10)
# Triage inbox items
for doc in inbox.get_untriaged():
if doc.word_count < 500:
inbox.archive(doc.id)
else:
inbox.move_to_later(doc.id)Simplified interfaces for common integration patterns.
from readwise_sdk.contrib import HighlightPusher
pusher = HighlightPusher(client)
# Push a single highlight
pusher.push(
text="Great quote from the article",
title="Article Title",
source_url="https://example.com/article",
)
# Push multiple highlights
pusher.push_batch([
{"text": "Quote 1", "title": "Book 1"},
{"text": "Quote 2", "title": "Book 2"},
])from readwise_sdk.contrib import DocumentImporter
importer = DocumentImporter(client)
# Import a URL
doc = importer.import_url("https://example.com/article")
# Import with tags
doc = importer.import_url(
"https://example.com/article",
tags=["to-read", "python"],
)from readwise_sdk.contrib import BatchSync, BatchSyncConfig
config = BatchSyncConfig(
batch_size=100,
state_file="sync_state.json",
)
sync = BatchSync(client, config=config)
# Sync with callback
def on_highlight(highlight):
save_to_database(highlight)
result = sync.sync_highlights(on_item=on_highlight)
print(f"Synced {result.synced_count} highlights")The CLI provides quick access to common operations.
# List recent highlights
readwise highlights list --limit 10
# Show a specific highlight
readwise highlights show 123456
# Export highlights
readwise highlights export -f markdown -o highlights.md
readwise highlights export -f json -o highlights.json# List books
readwise books list --limit 20
# Show book details
readwise books show 123# View inbox
readwise reader inbox --limit 50
# Save a URL
readwise reader save "https://example.com/article"
# Archive a document
readwise reader archive abc123
# Get reading stats
readwise reader stats# Generate daily digest
readwise digest daily -f markdown
# Generate weekly digest
readwise digest weekly -o weekly.md
# Generate book digest
readwise digest book 12345 -o book-notes.md# Full sync
readwise sync full --output-dir ./data
# Incremental sync
readwise sync incremental --state-file sync.json# Clone the repository
git clone https://github.com/EvanOman/readwise-plus.git
cd readwise-plus
# Install dependencies
just install
# Run all checks (format, lint, type-check, test)
just fc
# Run tests only
just test
# Run specific test file
uv run pytest tests/v2/test_client.pyContributions are welcome! Please follow these guidelines:
- Fork the repository and create a feature branch
- Follow conventional commits for commit messages:
feat(scope): add new featurefix(scope): fix a bugdocs: update documentation
- Run
just fcbefore committing to ensure all checks pass - Write tests for new functionality
- Submit a pull request with a clear description
See AGENTS.md for detailed development guidelines.
MIT