# Gamma23 Python SDK

The official Python SDK for **Gamma23** — financial infrastructure for AI agents.

Give your AI agents the ability to spend money safely, with policy guardrails, budget limits, and full auditability.

## Installation

```bash
pip install gamma23
```

## Quick Start

```python
from gamma23 import Gamma23

client = Gamma23(api_key="gm23_your_api_key")

# Declare a spending intent
intent = client.spend_intents.create(
    goal="Purchase annual Notion license",
    budget=96.00,
    currency="USD",
    merchant="Notion",
    category="software",
)

print(f"Intent {intent.id}: {intent.status}")
print(f"Policy decision: {'approved' if intent.policy_decision.allowed else 'denied'}")

# If approved, execute the spend
if intent.spend_token:
    result = client.spend_intents.execute(
        intent.id,
        spend_token=intent.spend_token,
    )
    print(f"Transaction {result.transaction_id}: {result.status}")
```

## Authentication

Pass your API key directly or set it as an environment variable:

```python
# Option 1: Pass directly
client = Gamma23(api_key="gm23_your_api_key")

# Option 2: Environment variable
# export GAMMA23_API_KEY=gm23_your_api_key
client = Gamma23()
```

The base URL defaults to `https://gamma23.app` and can be overridden via the `GAMMA23_API_URL` environment variable or the `base_url` parameter.

## API Reference

### Spend Intents

Spend intents let agents declare what they want to buy. Gamma23 evaluates the request against your policies and returns an approval (with a spend token) or denial.

```python
# Create a spend intent
intent = client.spend_intents.create(
    goal="Book a flight to London",
    budget=350.00,
    currency="GBP",
    merchant="British Airways",
    category="travel",
    domain="britishairways.com",
    metadata={"trip_id": "abc-123"},
    idempotency_key="unique-request-id",
)

# Retrieve an intent
intent = client.spend_intents.get("si_abc123")

# Cancel a pending intent
intent = client.spend_intents.cancel("si_abc123")

# Execute an approved intent
result = client.spend_intents.execute(
    "si_abc123",
    spend_token=intent.spend_token,
)
```

### Payments

Direct payment requests for cases where the amount and merchant are already known.

```python
# Create a payment request
payment = client.payments.create(
    amount=29.99,
    merchant="GitHub",
    domain="github.com",
    category="software",
    reason="Monthly GitHub Team subscription",
    evidence_links=["https://github.com/pricing"],
)

# Execute the payment
result = client.payments.execute(
    payment.id,
    spend_token=payment.spend_token,
)
```

### Agents

Query agent-level information like budgets.

```python
budget = client.agents.get_budget("agent_abc123")

print(f"Budget: {budget.remaining}/{budget.total_budget} {budget.currency}")
print(f"Resets at: {budget.resets_at}")
```

## Error Handling

The SDK raises typed exceptions for different failure modes:

```python
from gamma23 import Gamma23, Gamma23Error, AuthenticationError, RateLimitError

client = Gamma23(api_key="gm23_your_api_key")

try:
    intent = client.spend_intents.create(goal="Buy something", budget=100.0)
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited — retry after a moment: {e}")
except Gamma23Error as e:
    print(f"API error [{e.status_code}]: {e.message}")
    print(f"Error code: {e.code}")
    print(f"Request ID: {e.request_id}")
```

| Exception | HTTP Status | When |
|---|---|---|
| `AuthenticationError` | 401 | Invalid or missing API key |
| `NotFoundError` | 404 | Resource does not exist |
| `ValidationError` | 422 | Invalid request parameters |
| `RateLimitError` | 429 | Too many requests |
| `Gamma23Error` | Any | Base class for all errors |

## Retries

The client automatically retries requests on transient errors (HTTP 429 and 5xx) with exponential backoff. Configure via `max_retries`:

```python
client = Gamma23(api_key="gm23_...", max_retries=5, timeout=60.0)
```

## Context Manager

The client can be used as a context manager to ensure the underlying HTTP connection is closed:

```python
with Gamma23(api_key="gm23_...") as client:
    intent = client.spend_intents.create(goal="Buy tool", budget=50.0)
```

## Type Hints

The SDK is fully typed and ships with a `py.typed` marker. All responses are returned as frozen dataclasses:

- `SpendIntent` — A declared spending intent
- `PaymentRequest` — A payment request
- `ExecuteResult` — Result of executing a spend/payment
- `AgentBudget` — Budget information for an agent
- `PolicyDecision` — Policy evaluation result

## Async Support

This SDK uses [httpx](https://www.python-httpx.org/) under the hood. An async client is planned for a future release. In the meantime, you can run the sync client in a thread pool:

```python
import asyncio
from gamma23 import Gamma23

client = Gamma23(api_key="gm23_...")

async def main():
    loop = asyncio.get_event_loop()
    intent = await loop.run_in_executor(
        None,
        lambda: client.spend_intents.create(goal="Buy tool", budget=50.0),
    )
    print(intent)

asyncio.run(main())
```

## License

MIT
