> For the complete documentation index, see [llms.txt](https://docs.spacecoin.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.spacecoin.org/spacerouter-proxy/service-user-guide/python-sdk.md).

# Python SDK

### Install

```bash
pip install spacerouter
```

Requires Python 3.10 or later.

### Synchronous client

```python
from spacerouter import SpaceRouter
from spacerouter.payment import SpaceRouterSPACE

consumer = SpaceRouterSPACE(
    gateway_url="https://gateway.spacerouter.org",
    proxy_url="http://gateway.spacerouter.org:8080",
    private_key="0xYOUR_PRIVATE_KEY",
)

with SpaceRouter(
    consumer.address.lower(),                  # wallet address as first positional arg
    gateway_url="http://gateway.spacerouter.org:8080",
    payment=consumer,
    auto_settle=True,
    region="KR",
    ip_type="residential",
) as router:
    response = router.get("https://httpbin.org/ip")
    print(response.json())
```

### Constructor

```python
SpaceRouter(
    payer_address: str,                       # consumer wallet (lowercase 0x-hex)
    *,
    gateway_url: str = "https://gateway.spacerouter.org",
    payment: SpaceRouterSPACE,                # required — signs per-request challenges
    auto_settle: bool = False,                # sync receipts after each request
    protocol: Literal["http"] = "http",       # "http" only — socks5 not supported in v1.5+
    region: str | None = None,
    ip_type: str | None = None,
    timeout: float = 30.0,
)
```

### HTTP methods

Each method takes a URL and forwards keyword arguments to `httpx`:

```python
router.get(url, **kwargs)
router.post(url, json=..., **kwargs)
router.put(url, **kwargs)
router.patch(url, **kwargs)
router.delete(url, **kwargs)
router.head(url, **kwargs)
router.request(method, url, **kwargs)
```

### Per-request routing override

```python
kr_router = router.with_routing(region="KR", ip_type="residential")
us_router = router.with_routing(region="US")

kr_router.get("https://httpbin.org/ip")
```

### Async client

```python
import asyncio
from spacerouter import AsyncSpaceRouter
from spacerouter.payment import SpaceRouterSPACE

async def main():
    consumer = SpaceRouterSPACE(
        gateway_url="https://gateway.spacerouter.org",
        proxy_url="http://gateway.spacerouter.org:8080",
        private_key="0xYOUR_PRIVATE_KEY",
    )
    async with AsyncSpaceRouter(
        consumer.address.lower(),
        gateway_url="http://gateway.spacerouter.org:8080",
        payment=consumer,
        auto_settle=True,
    ) as router:
        response = await router.get("https://httpbin.org/ip")
        print(await response.json())

asyncio.run(main())
```

### Manual signing (advanced)

If you can't use the bundled `SpaceRouter` / `AsyncSpaceRouter` clients, you can build the four `X-SpaceRouter-*` headers yourself and stamp them on the proxy CONNECT.

```python
from spacerouter.payment import SpaceRouterSPACE

consumer = SpaceRouterSPACE(
    gateway_url="https://gateway.spacerouter.org",
    proxy_url="http://gateway.spacerouter.org:8080",
    private_key="0xYOUR_PRIVATE_KEY",
)

challenge = await consumer.request_challenge()
headers = consumer.build_auth_headers(challenge)
# … attach `headers` to the proxy CONNECT request

# Sync any pending Leg-1 receipts on chain
result = await consumer.sync_receipts()
print(result["accepted"], result["pending_count"])
```

See the full walk-through in [Pay with SPACE](https://claude.ai/local_sessions/pay-with-space-v1.5.md).

### Errors

Every SpaceRouter error subclasses `SpaceRouterError`:

<table><thead><tr><th width="225.328125">Class</th><th width="85.15234375">HTTP</th><th>Raised when</th></tr></thead><tbody><tr><td><code>AuthenticationError</code></td><td>407</td><td>Payment headers missing or challenge signature rejected.</td></tr><tr><td><code>QuotaExceededError</code></td><td>402</td><td>Escrow balance below the request's price, or legacy <code>Proxy-Authorization: Basic</code> detected (<code>api_key_auth_deprecated</code>).</td></tr><tr><td><code>RateLimitError</code></td><td>429</td><td>Too many requests. Has <code>retry_after</code>.</td></tr><tr><td><code>NoNodesAvailableError</code></td><td>503</td><td>No Provider matches your region/type filter.</td></tr><tr><td><code>UpstreamError</code></td><td>502</td><td>Provider couldn't reach the target site.</td></tr></tbody></table>

```python
from spacerouter import SpaceRouter, NoNodesAvailableError

try:
    router.get("https://httpbin.org/ip")
except NoNodesAvailableError:
    print("No matching nodes — try a different region")
```

### Configuration via environment

The CLI and SDK both read these:

<table><thead><tr><th width="265.38671875">Variable</th><th>Purpose</th></tr></thead><tbody><tr><td><code>SR_GATEWAY_URL</code></td><td>Override the gateway hostname (mostly for testing).</td></tr><tr><td><code>SR_GATEWAY_MANAGEMENT_URL</code></td><td>Management API endpoint (<code>/auth/challenge</code>, <code>/leg1/*</code>).</td></tr><tr><td><code>SR_ESCROW_PRIVATE_KEY</code></td><td>Wallet key for deposit/withdraw and per-request signing.</td></tr><tr><td><code>SR_ESCROW_CONTRACT_ADDRESS</code></td><td><code>TokenPaymentEscrow</code> contract address.</td></tr><tr><td><code>SR_ESCROW_CHAIN_RPC</code></td><td>Creditcoin RPC for on-chain calls.</td></tr></tbody></table>
