Metadata-Version: 2.5
Name: coinscan-sdk
Version: 0.1.0
Summary: Official Python client for the CoinScan API: token scans, holders, bubble maps, wallets, charts and market data for Solana, Ethereum, BSC and Base.
Project-URL: Homepage, https://coinscan.tech
Project-URL: Documentation, https://coinscan.tech/docs/sdks
Project-URL: API reference, https://coinscan.tech/docs/reference
Project-URL: Pricing, https://coinscan.tech/pricing
Author-email: PIRB <contact@pirb.tech>
License-Expression: MIT
License-File: LICENSE
Keywords: api,base,bsc,coinscan,crypto,ethereum,honeypot,pump.fun,rug check,sdk,solana,token scanner
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1,>=0.24
Requires-Dist: typing-extensions>=4.5; python_version < '3.11'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# coinscan-sdk

Official Python client for the [CoinScan API](https://coinscan.tech): scan any token on Solana, Ethereum, BSC, Base and more for price, liquidity, holders, snipers, bundles, LP lock, honeypot and tax checks, dev history and an AI rug estimate; map holders and bubble clusters; read wallet PnL; render charts; pull market and launchpad data.

```bash
pip install coinscan-sdk
```

Imported as `coinscan`. Python 3.9+. One dependency (`httpx`). Sync and async clients, typed responses, automatic retries on rate limits, and your remaining credits after every call.

## Quickstart

Get a free key (25 scans a day) at [coinscan.tech/signup](https://coinscan.tech/signup), or from Python:

```python
from coinscan import CoinScan

print(CoinScan.signup(email="you@example.com")["api_key"])   # shown once
```

```python
from coinscan import CoinScan

cs = CoinScan("cs_live_...")          # or set COINSCAN_API_KEY
scan = cs.scan("6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN")

print(scan["name"], scan["market"]["mcap"], scan["market"]["liquidity"])
print("bundles", scan["holders"]["bundle_pct"], "snipers", scan["holders"]["sniper_pct"])
print("rug probability", scan["ai_predictions"]["p_rug"])
print(cs.last_usage.remaining, "credits left today")
```

### Async

```python
import asyncio
from coinscan import AsyncCoinScan

async def main():
    async with AsyncCoinScan() as cs:
        scans = await asyncio.gather(*(cs.scan(a) for a in ["6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
                                                              "0x6982508145454Ce325dDbE47a25d4ec3d2311933"]))
        for s in scans:
            print(s["symbol"], s["flags"])

asyncio.run(main())
```

## What you can call

| method | what it returns | credits |
|-|-|-|
| `cs.scan(address, chain=None)` | full token scan (dict) | 10 |
| `cs.scan_lp_lock(address)` | finishes a scan made with `lp_defer=True` | 6 |
| `cs.detect(address)` | `{"address", "chain"}` from the address shape | 0 |
| `cs.resolve_ticker("PEPE")` | candidate contracts ranked by liquidity | 2 |
| `cs.resolve_pair(chain, pair)` | the token behind a pool | 0 |
| `cs.major("BTC")` | price, cap, supply, ATH of a major coin | 0 |
| `cs.mcap_batch([addr, ...])` | `{address: mcap}` for up to 500 tokens | 1 |
| `cs.max_mcap_batch(items)` | highest cap since a timestamp | 3 |
| `cs.lore(address)`, `cs.community(address)` | backstory; X community stats | 4 |
| `cs.search("cat")` | DexScreener pairs | 0 |
| `cs.chart(network, pool, plot_type="ta")` | PNG bytes | 3 |
| `cs.subscan.holders(token, chain=)` | top holders report | 1 |
| `cs.subscan.holders_map(token, chain=)` | holders by behaviour | 1 |
| `cs.subscan.whale_map(token, chain=)` | holders by size | 2 |
| `cs.subscan.bubble_map(token, chain=)` | `{"messages", "image": PNG bytes}` | 5 |
| `cs.subscan.early_buyers(token, chain=)` | first 50 buyers and what they did | 2 |
| `cs.subscan.wallet_map(token, chain=)` | holders labelled bot, insider, smart money | 1 |
| `cs.subscan.kol_holders(token)` | influencer wallets holding (Solana) | 1 |
| `cs.subscan.top_holder_bags(token)` | top holders' other pump.fun bags | 1 |
| `cs.subscan.overlap(token1, token2)` | wallets holding both (Solana) | 2 |
| `cs.subscan.dev(address, chain=)` | deployer launch history | 4 |
| `cs.subscan.top_traders(token, chain=)` | traders by realized PnL (list of dicts) | 1 |
| `cs.subscan.wallet_stats(wallet)` | 30-day stats across chains | 3 |
| `cs.subscan.pumpfun_meta()` | trending pump.fun words | 0 |
| `cs.wallet.pnl(wallet, chain=)` | PnL report | 5 |
| `cs.wallet.floor(token, chain=)` | holders' entry caps, supply in loss | 1 |
| `cs.wallet.token_balance(wallet, token, chain=)` | float | 1 |
| `cs.wallet.token_balances(token, wallets, chain=)` | `{wallet: balance}` | 1 |
| `cs.wallet.tx(hash, chain=)` | `{"from", "to", "value_wei", "block_number"}` | 1 |
| `cs.market.macro()`, `.news()`, `.calendar()`, `.gas()` | market data | 0 |
| `cs.market.dex_paid()`, `.dex_trending()`, `.dex_paid_status(token)` | DexScreener signals | 0 |
| `cs.market.pumpfun_graduates()`, `.pumpfun_search(q)` | pump.fun | 0 |
| `cs.market.treemap()`, `.top_coins_card()`, `.fear_greed_image()`, `.pnl_card(...)` | PNG bytes | 0 |
| `cs.launchpads.summary()`, `.stats()`, `.chart()`, `.heat()` | launchpad volume and heat | 0 |
| `cs.account.me()`, `.usage()`, `.rotate_key()` | your plan, usage, keys | 0 |
| `cs.billing.plans()`, `.create_invoice(...)`, `.wait_for_payment(id)` | plans and USDT/USDC invoices | 0 |

Field-by-field documentation: [coinscan.tech/docs](https://coinscan.tech/docs).

## Text reports

Holder, wallet and deployer routes return formatted reports (Telegram-style HTML), ready to post in a bot. `to_text` turns them into plain text:

```python
from coinscan import CoinScan, to_text

cs = CoinScan()
print(to_text(cs.subscan.dev("6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN")))
```

## Images

```python
from pathlib import Path

Path("chart.png").write_bytes(cs.chart("solana", "PAIR_ADDRESS", timeframe="hour", plot_type="ta"))

bubble = cs.subscan.bubble_map("6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN")
if bubble["image"]:
    Path("bubble.png").write_bytes(bubble["image"])
```

## Credits, limits and errors

`cs.last_usage` holds the usage headers of the last metered call: `cost`, `limit`, `remaining`, `reset` (next 00:00 UTC), `rate_limit`, `rate_remaining`.

```python
from coinscan import CoinScan, QuotaExceededError, NotFoundError, UpstreamTimeoutError

cs = CoinScan()
try:
    scan = cs.scan("So11111111111111111111111111111111111111112")
except NotFoundError:
    print("no such token")
except QuotaExceededError as e:
    print("out of credits until", e.reset_at, "upgrade:", e.upgrade_url)
except UpstreamTimeoutError:
    print("a data provider was slow; try again")
```

| exception | when |
|-|-|
| `AuthenticationError` | 401: missing or unknown key |
| `NotFoundError` | 404: token, pair or data not found |
| `ValidationError` | 422: bad input |
| `RateLimitError` | 429 per-minute limit (retried automatically, then raised; has `retry_after`) |
| `QuotaExceededError` | 429 daily credits spent (`reset_at`, `upgrade_url`) |
| `UpstreamTimeoutError` | a 45 s upstream deadline passed |
| `InternalServerError` | 5xx (502/503/504 retried; credits are refunded) |
| `APIConnectionError`, `APITimeoutError` | network problems |

All inherit from `CoinScanError`. Retries: `CoinScan(max_retries=2)` by default; `0` turns them off. The default timeout is 90 s because a scan can take up to 60.

## Paying from code

```python
cs = CoinScan()
inv = cs.billing.create_invoice("starter", chain="solana", token="USDC")
print(f"send exactly {inv['amount']} {inv['token']} to {inv['pay_to']}")
print(inv["payment_uri"])                     # Solana Pay / EIP-681 link
paid = cs.billing.wait_for_payment(inv["id"])
print(paid["status"], paid.get("plan_expires_at"))
```

## Command line

```bash
export COINSCAN_API_KEY=cs_live_...
coinscan scan 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN
coinscan holders 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN
coinscan chart solana PAIR_ADDRESS --plot-type ta > chart.png
coinscan me
```

## Configuration

| setting | argument | environment variable | default |
|-|-|-|-|
| API key | `CoinScan(api_key)` | `COINSCAN_API_KEY` | none |
| base URL | `base_url=` | `COINSCAN_BASE_URL` | `https://api.coinscan.tech` |
| timeout | `timeout=` | | 90 s |
| retries | `max_retries=` | | 2 |
| HTTP client | `http_client=httpx.Client(...)` | | one per client |

## Links

- Docs: https://coinscan.tech/docs
- Pricing: https://coinscan.tech/pricing (free 25 scans a day; from $50 a month, paid in USDT or USDC)
- MCP server for Claude and Cursor: https://coinscan.tech/docs/mcp
- Support: contact@pirb.tech

MIT licensed.
