> ## Documentation Index
> Fetch the complete documentation index at: https://polargrid.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Python Quickstart

> Get started with the PolarGrid Python SDK

# Python SDK

The official Python SDK for PolarGrid with async and sync clients.

## Installation

```bash theme={null}
pip install polargrid-sdk
```

## Quick Start

### Async Client (Recommended)

```python theme={null}
import asyncio
from polargrid import PolarGrid

async def main():
    # Auto-select best region by latency
    client = await PolarGrid.create(api_key="pg_your_api_key")
    
    print(f"Connected to: {client.get_region_name()}")  # e.g., "Toronto"

    response = await client.chat_completion({
        "model": "qwen-3.5-27b",
        "messages": [
            {"role": "user", "content": "Hello!"}
        ]
    })

    print(response.choices[0].message.content)

asyncio.run(main())
```

### Sync Client

```python theme={null}
from polargrid import PolarGridSync

client = PolarGridSync(api_key="pg_your_api_key", region="toronto")

response = client.chat_completion({
    "model": "qwen-3.5-27b",
    "messages": [{"role": "user", "content": "Hello!"}]
})

print(response.choices[0].message.content)
```

## Configuration

```python theme={null}
# Async client with auto-routing (recommended)
client = await PolarGrid.create(
    api_key="pg_your_api_key",  # or set POLARGRID_API_KEY env var
    debug=True,
)

# Sync constructor with explicit region
client = PolarGrid(
    api_key="pg_your_api_key",
    
    # Region alias: 'toronto', 'montreal', 'vancouver', 'new-york', 'dallas', 'san-francisco'
    # Or explicit ID: yto-01, yul-01, yul-02, yvr-02, nyc-01, nyc-02, dfw-01, dfw-02, sfo-01, lax-01, sea-01, chi-01, phx-01, was-01, mia-01, sfo-03
    region="vancouver",
    
    # Request timeout in seconds (default: 30.0)
    timeout=30.0,
    
    # Max retry attempts (default: 3)
    max_retries=3,
    
    # Enable debug logging
    debug=True,
    
    # Use mock data for development
    use_mock_data=False,
)
```

## Auto-Routing

```python theme={null}
# Calls the autorouter which returns the optimal edge based on your origin
client = await PolarGrid.create(api_key="pg_...", debug=True)

# [PolarGrid] Auto-routing: selected Toronto (yto-01)

print(client.get_region_id())   # 'yto-01'
print(client.get_region_name()) # 'Toronto'
```

## Streaming

```python theme={null}
async for chunk in client.chat_completion_stream({
    "model": "qwen-3.5-27b",
    "messages": [{"role": "user", "content": "Tell me a story"}],
}):
    content = chunk.choices[0].delta.content
    if content:
        print(content, end="", flush=True)
```

## Response Metadata (latency)

PolarGrid attaches per-request metadata (region, latency breakdown) under `response.pg_metadata`. It is **optional** — fields may be `None`, and on the non-stream path `latency_ms` is commonly `None`. Always read it through the typed attribute and guard for `None`; never index a top-level `latency_ms` key (it does not exist and raises `KeyError`).

```python theme={null}
response = await client.chat_completion({
    "model": "qwen-3.5-27b",
    "messages": [{"role": "user", "content": "Hello!"}],
})

text = response.choices[0].message.content

meta = response.pg_metadata
if meta is not None:
    print(f"region={meta.region} latency_ms={meta.latency_ms}")  # latency_ms may be None
```

Streaming chat chunks (`ChatCompletionChunk`) do **not** carry `pg_metadata` — only the non-stream `chat_completion` response exposes it. If you need region/latency metadata on a streamed request, issue a non-stream call, or read the timing from your own client-side measurements.

## Mock Mode

```python theme={null}
client = PolarGrid(
    use_mock_data=True,  # No API calls
    debug=True,
)

# All methods return realistic mock data
response = await client.chat_completion({
    "model": "qwen-3.5-27b",
    "messages": [{"role": "user", "content": "Hello!"}]
})
```

## Type Hints

The SDK uses Pydantic models with full type hints:

```python theme={null}
from polargrid.types import (
    ChatCompletionRequest,
    ChatCompletionResponse,
    Message,
)

# Request with typed model
request = ChatCompletionRequest(
    model="qwen-3.5-27b",
    messages=[Message(role="user", content="Hello!")],
    max_tokens=100,
)

# Or use dict (auto-converted)
response = await client.chat_completion({
    "model": "qwen-3.5-27b",
    "messages": [{"role": "user", "content": "Hello!"}],
})
```

## Environment Variables

```bash theme={null}
export POLARGRID_API_KEY=pg_your_api_key
export POLARGRID_BASE_URL=https://api.yto-01.edge.polargrid.ai  # Optional. Pins the SDK to a specific edge. Leave unset and call PolarGrid.create() to auto-discover the fastest region via https://autorouter.polargrid.ai/v1/route.
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Full Reference" icon="book" href="/sdks/python/reference">
    Complete API reference
  </Card>

  <Card title="Voice Guide" icon="microphone" href="/guides/voice">
    Text-to-speech and speech-to-text
  </Card>
</CardGroup>
