A modern, type-safe Python client library for the CryptoPanic API. This library provides a clean, intuitive interface to access cryptocurrency news and market data.
- 🚀 Type-safe: Built with Pydantic for robust data validation
- 🎯 Easy to use: Simple, Pythonic API design
- 🔒 Error handling: Comprehensive exception handling for all API error codes
- 📦 Well tested: High test coverage with pytest
- 🛠️ Developer friendly: Full type hints, comprehensive documentation
- ⚡ Async ready: Built on requests for reliable HTTP handling
pip install cryptopanicfrom cryptopanic import CryptoPanicClient
# Initialize the client with your API token
client = CryptoPanicClient(auth_token="your_api_token_here")
# Get news posts for Bitcoin and Ethereum
posts = client.get_posts(
currencies=["BTC", "ETH"],
filter="rising"
)
# Iterate through posts
for post in posts.results:
print(f"{post.title} - {post.published_at}")
print(f"Source: {post.source.title}")
print(f"URL: {post.url}")
print(f"Panic Score: {post.panic_score}")
print("-" * 50)The main client class for interacting with the CryptoPanic API.
client = CryptoPanicClient(
auth_token: str, # Your CryptoPanic API token (required)
timeout: int = 30 # Request timeout in seconds (optional)
)Retrieve a list of news posts with various filtering options.
Parameters:
public(bool, optional): Enable public mode (uses non-user-specific settings)currencies(list[str], optional): Filter by currency codes (e.g.,["BTC", "ETH"])regions(list[str], optional): Filter by regions (e.g.,["en", "fr"])filter(str, optional): Filter by type:"rising","hot","bullish","bearish","important","saved","lol"kind(str, optional): Filter by news kind:"news","media","all"(default:"all")following(bool, optional): Filter by sources you follow (PRIVATE API only)last_pull(datetime | str, optional): Limit search to last pull time (ISO 8601) - Enterprise onlypanic_period(str, optional): Include panic score for period:"1h","6h","24h"- Enterprise onlypanic_sort(str, optional): Sort by panic score:"asc"or"desc"(requirespanic_period) - Enterprise onlysize(int, optional): Items per page (1-500, max 500) - Enterprise onlywith_content(bool, optional): Filter items with full content - Enterprise onlysearch(str, optional): Search by keyword - Enterprise onlyformat(str, optional): Response format (e.g.,"rss") - returns max 20 items
Returns: PostsResponse object containing:
results: List ofPostobjectsnext: URL for next page (orNone)previous: URL for previous page (orNone)
Example:
# Get rising news for Bitcoin
posts = client.get_posts(
currencies=["BTC"],
filter="rising"
)
# Get public news in English and French
posts = client.get_posts(
public=True,
regions=["en", "fr"]
)
# Search for specific keywords (Enterprise plan)
posts = client.get_posts(
search="bitcoin halving"
)Retrieve your portfolio. Available only for GROWTH and ENTERPRISE API plans.
Returns: PortfolioResponse object
Example:
portfolio = client.get_portfolio()Represents a news post from CryptoPanic.
class Post:
id: int
slug: str
title: str
description: str
published_at: datetime
created_at: datetime
kind: str # "news", "media", "blog", "twitter", "reddit"
source: Source
original_url: str
url: str
image: str | None
instruments: list[Instrument]
votes: Votes
panic_score: int | None # 0-100
panic_score_1h: int | None # 0-100
author: str | None
content: Content | NoneRepresents a cryptocurrency instrument.
class Instrument:
code: str # e.g., "BTC"
title: str # e.g., "Bitcoin"
slug: str
url: str
market_cap_usd: float | None
price_in_usd: float | None
price_in_btc: float | None
price_in_eth: float | None
price_in_eur: float | None
market_rank: int | NoneRepresents a news source.
class Source:
title: str
region: str # Language code (e.g., "en", "fr")
domain: str
type: str # "feed", "blog", "twitter", "media", "reddit"Represents vote counts for a post.
class Votes:
negative: int
positive: int
important: int
liked: int
disliked: int
lol: int
toxic: int
saved: int
comments: intThe library provides specific exception classes for different error scenarios:
from cryptopanic import (
CryptoPanicClient,
CryptoPanicAuthenticationError,
CryptoPanicForbiddenError,
CryptoPanicRateLimitError,
CryptoPanicServerError,
CryptoPanicAPIError,
)
client = CryptoPanicClient(auth_token="your_token")
try:
posts = client.get_posts()
except CryptoPanicAuthenticationError:
print("Invalid API token")
except CryptoPanicRateLimitError:
print("Rate limit exceeded. Please wait before making more requests.")
except CryptoPanicForbiddenError:
print("Access forbidden. Check your API plan limits.")
except CryptoPanicServerError:
print("Server error. Please try again later.")
except CryptoPanicAPIError as e:
print(f"API error: {e}")CryptoPanicAPIError: Base exception for all API errorsCryptoPanicAuthenticationError: Raised on 401 UnauthorizedCryptoPanicForbiddenError: Raised on 403 Forbidden (rate limit or access denied)CryptoPanicRateLimitError: Raised on 429 Too Many RequestsCryptoPanicServerError: Raised on 500 Internal Server Error
posts = client.get_posts(
currencies=["BTC", "ETH", "SOL"],
filter="hot"
)
for post in posts.results:
print(f"{post.title}")
for instrument in post.instruments:
print(f" - {instrument.code}: ${instrument.price_in_usd}")# Enterprise plan only
posts = client.get_posts(
currencies=["BTC"],
with_content=True
)
for post in posts.results:
if post.content:
print(f"Title: {post.title}")
print(f"Clean content: {post.content.clean}")posts = client.get_posts(currencies=["BTC"])
# Process first page
for post in posts.results:
print(post.title)
# Get next page (you would need to parse the URL or implement pagination helper)
if posts.next:
print(f"Next page: {posts.next}")# Get RSS feed (max 20 items)
posts = client.get_posts(
currencies=["BTC"],
format="rss"
)# Clone the repository
git clone https://github.com/guilyx/cryptopanic.git
cd cryptopanic
# Install in development mode
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install# Run all tests (unit tests only, uses mocked requests)
pytest
# Run with coverage
pytest --cov=cryptopanic --cov-report=html
# Run specific test file
pytest tests/test_client.py
# Run integration tests (requires CRYPTOPANIC_AUTH_TOKEN env var)
CRYPTOPANIC_AUTH_TOKEN=your_token pytest tests/test_integration.py
# Run all tests including integration tests
CRYPTOPANIC_AUTH_TOKEN=your_token pytestNote: Unit tests use mocked API responses and don't require a real API token. Integration tests make real API calls and require the CRYPTOPANIC_AUTH_TOKEN environment variable to be set.
# Format code
black .
# Lint code
ruff check .
# Type checking
mypy cryptopanicContributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass and code is formatted
- Commit your changes (following the commit message guidelines)
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- CryptoPanic for providing the API
- All contributors who help improve this library
- Feature Development: Work happens on feature branches
- Merge to Master: Features are merged to
masterafter review - Release Candidates: When enough features accumulate (typically 3-5), create a release candidate:
# Update version in pyproject.toml (e.g., 0.2.0rc1) git add pyproject.toml CHANGELOG.md git commit -m "chore: prepare release 0.2.0rc1" git tag v0.2.0rc1 git push origin master --tags
- Optional: Create a GitHub Release marked as "pre-release" for testing (won't publish to PyPI)
- Test: Install and test the release candidate:
pip install cryptopanic==0.2.0rc1
- Final Release: After testing passes, create final release:
# Update version in pyproject.toml (e.g., 0.2.0) git add pyproject.toml CHANGELOG.md git commit -m "chore: release 0.2.0" git tag v0.2.0 git push origin master --tags
- GitHub Release: Create a GitHub Release with the tag (via UI or
gh release create v0.2.0) - Auto-publish: Workflow automatically publishes final releases to PyPI (pre-releases are skipped)
PyPI Trusted Publishing:
- Create GitHub Environment: Settings → Environments → New (
pypi) - Configure at https://pypi.org/manage/account/publishing/:
- Project:
cryptopanic - Workflow:
publish.yml - Environment:
pypi - Repository:
guilyx/cryptopanic
- Project:
Version Format: Follow Semantic Versioning (MAJOR.MINOR.PATCH)
For issues, questions, or contributions, please open an issue on GitHub.
See CHANGELOG.md for detailed release notes.