Metadata-Version: 2.4
Name: inbounter
Version: 1.0.0
Summary: Official Python server SDK for Inbounter
Project-URL: Homepage, https://inbounter.com
Project-URL: Repository, https://github.com/inbounter/inbounter-python
Project-URL: Issues, https://github.com/inbounter/inbounter-python/issues
Author: Inbounter
License: MIT
Keywords: agents,ai,email,inbounter,inboxes,sdk,sms
Requires-Python: >=3.10
Requires-Dist: requests>=2.31.0
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://inbounter.com/logos/inbounter_light.svg" />
    <source media="(prefers-color-scheme: light)" srcset="https://inbounter.com/logos/inbounter_dark.svg" />
    <img src="https://inbounter.com/logos/inbounter_dark.svg" alt="Inbounter" width="300" />
  </picture>
</p>

<p align="center">
  <b>Official Python SDK for <a href="https://inbounter.com">Inbounter</a></b><br/>
  Secure inbox infrastructure for AI agents — email, SMS, smart routing, and Shield Mode.
</p>

<p align="center">
  <a href="https://pypi.org/project/inbounter/">
    <img src="https://img.shields.io/pypi/v/inbounter.svg?style=flat-square" alt="PyPI Version" />
  </a>
  <a href="https://github.com/inbounter/inbounter/blob/main/LICENSE">
    <img src="https://img.shields.io/github/license/inbounter/inbounter.svg?style=flat-square" alt="License" />
  </a>
</p>

# Inbounter Python SDK

## What is Inbounter?

**Inbounter** is infrastructure that gives AI agents their own inboxes — email, SMS, and more — with built-in security and smart routing.

- 📬 **Inboxes** — Provision dedicated email & SMS inboxes for AI agents
- 🛡️ **Shield Mode** — Block spam, phishing, and unwanted messages automatically
- 🔀 **Smart Routing** — Route inbound messages with filters, AI extraction, and webhooks
- 📨 **Outbound** — Send emails and SMS directly from agent inboxes
- 🔗 **Webhooks** — Real-time event notifications for contacts, messages, and more
- 💳 **Credits** — Usage-based billing with auto-replenish

> [Get your API key](https://inbounter.com)

## Installation

```bash
pip install inbounter
```

Requires Python 3.10+.

## Quick Start

```python
from inbounter import Inbounter, SourceType

# Initialize the client
client = Inbounter("your-api-key")
client.set_workspace_id("wks_123")

# Create an inbox with automatic source provisioning
inbox = client.inboxes.create({
    "name": "support-agent",
    "sourceType": SourceType.EMAIL.value,
    "domain": "agents.yourdomain.com",
    "provisionSource": True,
})

print(inbox["id"])  # inb_abc123
```

## Inboxes

Create, manage, and send from dedicated agent inboxes.

### Create an inbox

```python
inbox = client.inboxes.create({
    "name": "sales-agent",
    "sourceType": SourceType.EMAIL.value,
    "domain": "agents.yourdomain.com",
    "provisionSource": True,
    "shieldEnabled": True,
})
```

### Get, update, and delete

```python
inbox = client.inboxes.get("inb_abc123")

inbox = client.inboxes.update("inb_abc123", {
    "name": "renamed-agent",
    "shieldEnabled": False,
})

client.inboxes.delete("inb_abc123")
```

### List inboxes

```python
inboxes = client.inboxes.list()
```

### Inbox stats

```python
stats = client.inboxes.get_stats("inb_abc123")
print(stats)
```

### List messages and threads

```python
messages = client.inboxes.list_messages("inb_abc123", {"limit": 20})

results = client.inboxes.search_messages("inb_abc123", {"q": "invoice"})

threads = client.inboxes.list_threads("inb_abc123")

thread = client.inboxes.get_thread("inb_abc123", "thr_xyz789")
```

### Send email from an inbox

```python
message = client.inboxes.send_email("inb_abc123", {
    "to": "customer@example.com",
    "subject": "Your order has shipped",
    "html": "<p>Hi! Your order #1234 is on the way.</p>",
})
```

### Send batch emails

```python
messages = client.inboxes.send_batch("inb_abc123", {
    "messages": [
        {
            "to": "alice@example.com",
            "subject": "Welcome!",
            "text": "Thanks for signing up.",
        },
        {
            "to": "bob@example.com",
            "subject": "Welcome!",
            "text": "Thanks for signing up.",
        },
    ]
})
```

### Link Gmail

```python
client.inboxes.link_gmail("inb_abc123", {
    "authCode": "4/0AX4XfW...",
})
```

## Messages

Retrieve messages and retry failed deliveries.

```python
# Get a single message
message = client.messages.get("msg_abc123")

# List all messages in the workspace
messages = client.messages.list({"limit": 50})

# List messages for a specific source
messages = client.messages.list_by_source("src_xyz789", {"limit": 20})

# Retry a failed delivery
client.messages.retry_delivery("msg_abc123", "dlv_456")
```

## Routes (Smart Routing)

Routes let you filter inbound messages, apply AI transformations, and deliver to destinations — all without writing backend code.

### Scoping

Routes are scoped to either an **inbox** or a **source**:

```python
inbox_scope = client.routes.scope_for_inbox("inb_abc123")
source_scope = client.routes.scope_for_source("src_xyz789")
```

### Create a route

```python
from inbounter import FilterOperator, TransformationType, DestinationType

scope = client.routes.scope_for_inbox(inbox["id"])

route = client.routes.create(scope, {
    "name": "Lead route",
    "enabled": True,
})
```

### List, update, delete, and reorder

```python
routes = client.routes.list(scope)

route = client.routes.update(scope, "rte_abc123", {
    "name": "Updated route",
})

client.routes.delete(scope, "rte_abc123")

client.routes.reorder(scope, ["rte_first", "rte_second", "rte_third"])
```

### Filters

Attach filters to control which messages match a route:

```python
client.routes.create_filter(route["id"], {
    "field": "subject",
    "operator": FilterOperator.CONTAINS.value,
    "value": "pricing",
})

filters = client.routes.list_filters(route["id"])

client.routes.update_filter(route["id"], "flt_abc123", {
    "operator": FilterOperator.STARTS_WITH.value,
    "value": "urgent",
})

client.routes.delete_filter(route["id"], "flt_abc123")
```

### Transformations (AI extraction, summarization, and more)

Apply AI-powered transformations to messages before they reach destinations:

```python
client.routes.create_transformation(route["id"], {
    "type": TransformationType.AI_EXTRACT.value,
    "outputKey": "lead",
    "config": {
        "fields": [
            {"name": "company", "description": "Company name", "type": "string"},
            {"name": "budget", "description": "Budget amount", "type": "number"},
        ]
    },
})

transformations = client.routes.list_transformations(route["id"])

client.routes.update_transformation(route["id"], "tfm_abc123", {
    "config": {"fields": [{"name": "company", "description": "Company", "type": "string"}]},
})

client.routes.delete_transformation(route["id"], "tfm_abc123")
```

### Destinations

Deliver matched messages to Slack, Discord, webhooks, CRMs, and more:

```python
destination = client.routes.create_destination(scope, route["id"], {
    "type": DestinationType.WEBHOOK.value,
    "name": "Agent webhook",
    "config": {"url": "https://example.com/webhook"},
})

destinations = client.routes.list_destinations(scope, route["id"])

client.routes.update_destination(scope, route["id"], "dst_abc123", {
    "name": "Updated webhook",
})

client.routes.test_destination(scope, route["id"], "dst_abc123")

client.routes.delete_destination(scope, route["id"], "dst_abc123")
```

### Full routing example

```python
from inbounter import (
    Inbounter, SourceType, FilterOperator,
    TransformationType, DestinationType,
)

client = Inbounter("your-api-key")
client.set_workspace_id("wks_123")

# 1. Create an inbox
inbox = client.inboxes.create({
    "name": "sales-agent",
    "sourceType": SourceType.EMAIL.value,
    "domain": "agents.yourdomain.com",
    "provisionSource": True,
})

# 2. Create a route
scope = client.routes.scope_for_inbox(inbox["id"])
route = client.routes.create(scope, {"name": "Lead route", "enabled": True})

# 3. Add a filter
client.routes.create_filter(route["id"], {
    "field": "subject",
    "operator": FilterOperator.CONTAINS.value,
    "value": "pricing",
})

# 4. Add AI extraction
client.routes.create_transformation(route["id"], {
    "type": TransformationType.AI_EXTRACT.value,
    "outputKey": "lead",
    "config": {
        "fields": [
            {"name": "company", "description": "Company", "type": "string"},
            {"name": "budget", "description": "Budget", "type": "number"},
        ]
    },
})

# 5. Deliver to a webhook
client.routes.create_destination(scope, route["id"], {
    "type": DestinationType.WEBHOOK.value,
    "name": "Agent webhook",
    "config": {"url": "https://example.com/webhook"},
})
```

## Webhooks

Receive real-time event notifications.

```python
# Create a webhook
webhook = client.webhooks.create({
    "url": "https://example.com/webhooks/inbounter",
    "events": ["message.received", "message.delivered"],
})

# Get a webhook
webhook = client.webhooks.get("whk_abc123")

# List all webhooks
webhooks = client.webhooks.list()

# Update a webhook
webhook = client.webhooks.update("whk_abc123", {
    "events": ["message.received"],
})

# Pause and resume
client.webhooks.pause("whk_abc123", reason="Maintenance window")
client.webhooks.resume("whk_abc123")

# Send a test event
client.webhooks.test("whk_abc123")

# Delete a webhook
client.webhooks.delete("whk_abc123")
```

## Sources

Manage inbound channels (email addresses, phone numbers, forms, etc.).

```python
# Create a source
source = client.sources.create({
    "type": SourceType.EMAIL.value,
    "address": "agent@agents.yourdomain.com",
})

# Get a source
source = client.sources.get("src_abc123")

# List sources
sources = client.sources.list()

# Update a source
source = client.sources.update("src_abc123", {"label": "Main inbox"})

# Verify a source (e.g. confirm DNS records)
source = client.sources.verify("src_abc123")

# Delete a source
client.sources.delete("src_abc123")
```

## Credits

View and configure usage-based credits for your workspace.

```python
# Get current credit balance and recent ledger entries
credits = client.credits.get(ledger_limit=10)
print(credits)

# Update auto-replenish settings
client.credits.update({
    "autoReplenishEnabled": True,
    "autoReplenishThreshold": 100.0,
    "autoReplenishAmount": 500.0,
})
```

## Shield Mode

Shield Mode is enabled per-inbox and automatically blocks spam, phishing, and unwanted messages before they reach your agent.

```python
inbox = client.inboxes.create({
    "name": "protected-agent",
    "sourceType": SourceType.EMAIL.value,
    "domain": "agents.yourdomain.com",
    "provisionSource": True,
    "shieldEnabled": True,
})
```

Messages flagged by Shield Mode receive a `QUARANTINED` status and are not delivered to routes or destinations.

## Configuration

```python
from inbounter import Inbounter

client = Inbounter("your-api-key", options={
    "base_url": "https://api.inbounter.com",  # Custom API base URL
    "timeout": 30,                             # Request timeout in seconds (default: 30)
    "max_retries": 3,                          # Max retries on 429/5xx (default: 3)
    "api_version": "v1",                       # API version (default: "v1")
})

# Set workspace context (required for most endpoints)
client.set_workspace_id("wks_123")

# Enable debug mode to log requests and responses
client.set_debug_mode(True)

# Set custom headers
client.set_header("X-Custom-Header", "value")
client.set_headers({"X-Foo": "bar", "X-Baz": "qux"})
```

## Error Handling

All errors extend `InbounterError` and include structured metadata:

```python
from inbounter import (
    InbounterError,
    APIError,
    AuthenticationError,
    RateLimitError,
    NetworkError,
    TimeoutError,
    ValidationError,
)

try:
    client.inboxes.get("inb_nonexistent")
except AuthenticationError as e:
    print(f"Auth failed: {e}, code={e.code}")
except RateLimitError as e:
    print(f"Rate limited: {e}, status={e.status_code}")
except TimeoutError as e:
    print(f"Request timed out: {e}")
except NetworkError as e:
    print(f"Network error: {e}")
except ValidationError as e:
    print(f"Validation error: {e}, data={e.data}")
except APIError as e:
    print(f"API error: {e}, status={e.status_code}, request_id={e.request_id}")
except InbounterError as e:
    print(f"General error: {e}")
```

| Exception             | Trigger                               |
| --------------------- | ------------------------------------- |
| `InbounterError`      | Base class for all SDK errors         |
| `APIError`            | Non-2xx response from the API         |
| `AuthenticationError` | Invalid or missing API key (401)      |
| `RateLimitError`      | Too many requests (429), after retries|
| `NetworkError`        | Connection or DNS failure             |
| `TimeoutError`        | Request exceeded timeout              |
| `ValidationError`     | Invalid input parameters              |

## Enums

The SDK exports typed enums for all constants used in payloads:

| Enum                   | Values                                                                                                     |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| `SourceType`           | `EMAIL`, `SMS`, `FORM`, `DISCORD`, `WHATSAPP`, `INSTAGRAM`, `TIKTOK`, `PHONE_CALL`, `VIDEO_CALL`          |
| `SourceStatus`         | `PENDING`, `ACTIVE`, `FAILED`, `DISABLED`                                                                  |
| `MessageStatus`        | `RECEIVED`, `PROCESSING`, `ROUTING`, `DELIVERED`, `PARTIAL`, `FAILED`, `DROPPED`, `QUARANTINED`            |
| `MessageDirection`     | `INBOUND`, `OUTBOUND`                                                                                      |
| `InboxStatus`          | `ACTIVE`, `DISABLED`                                                                                       |
| `WebhookStatus`        | `ACTIVE`, `PAUSED`, `BANNED`                                                                               |
| `FilterOperator`       | `contains`, `not_contains`, `equals`, `not_equals`, `regex`, `starts_with`, `ends_with`, `exists`, `not_exists` |
| `FilterLogic`          | `AND`, `OR`                                                                                                |
| `DestinationType`      | `SLACK`, `DISCORD`, `WEBHOOK`, `EMAIL`, `ZAPIER`, `CRM_HUBSPOT`, `CRM_SALESFORCE`, `CRM_ZENDESK`, `DATABASE` |
| `ExecutionMode`        | `PARALLEL`, `SEQUENTIAL`                                                                                   |
| `TransformationType`   | `AI_SUMMARY`, `AI_CATEGORIZE`, `AI_EXTRACT`, `APOLLO_ENRICHMENT`, `CLEARBIT_ENRICHMENT`, `CUSTOM_WEBHOOK`, `CUSTOM_CODE` |
| `CreditLedgerType`     | `REPLENISH`, `CONSUME`                                                                                     |
| `CreditLedgerReason`   | `INITIAL_PROVISION`, `AUTO_REPLENISH`, `MANUAL_ADJUSTMENT`, `INBOUND_MESSAGE`, `OUTBOUND_EMAIL`, `WEBHOOK_DELIVERY` |

```python
from inbounter import SourceType, FilterOperator, DestinationType, TransformationType

# Use .value when passing to API payloads
print(SourceType.EMAIL.value)           # "EMAIL"
print(FilterOperator.CONTAINS.value)    # "contains"
```

## Documentation

Full API reference and guides: **[inbounter.com/docs](https://inbounter.com/docs)**

---

## Other SDKs

| Language | Package | Install |
|----------|---------|---------|
| Node.js / TypeScript | [`@inbounter/node`](https://www.npmjs.com/package/@inbounter/node) | `npm install @inbounter/node` |

## Contributing

We welcome contributions!

1. **Fork** the repo and create your branch: `git checkout -b feat/awesome`
2. Add tests and update documentation as needed
3. Open a **PR** against `main`

## License

[MIT](LICENSE)
