Metadata-Version: 2.4
Name: permissio
Version: 0.1.0b1
Summary: Official Python SDK for the Permissio Partner API.
Project-URL: Homepage, https://docs.permissio.us
Project-URL: Documentation, https://docs.permissio.us
Project-URL: Repository, https://github.com/permissio/permissio-python
Project-URL: Changelog, https://github.com/permissio/permissio-python/blob/main/CHANGELOG.md
Author-email: Permissio <support@permissio.us>
License: MIT
Keywords: documents,esignature,permissio,sdk,signing
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.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.25.0
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# permissio

Official Python SDK for the [Permissio](https://permissio.us) Partner API. Build document-signing workflows directly into your product.

## Installation

```bash
pip install permissio
```

Requires Python 3.9+ and [httpx](https://www.python-httpx.org/).

## Quick start

```python
from permissio import Permissio

client = Permissio(api_key="sk_live_…")  # or sk_test_… for sandbox

# 1. Upload a template PDF
result = client.templates.get_upload_url()
import httpx
httpx.put(
    result["upload_url"],
    content=open("nda.pdf", "rb").read(),
    headers={"Content-Type": "application/pdf"},
)

# 2. Create a template
template = client.templates.create(
    name="NDA — Mutual Confidentiality Agreement",
    document_url=result["object_path"],
    recipients=[
        {"role_name": "Disclosing Party", "signing_order": 1},
        {"role_name": "Receiving Party",  "signing_order": 2},
    ],
    variables=[
        {"name": "effective_date", "type": "date",   "required": True},
        {"name": "party_a_name",   "type": "string", "required": True},
    ],
)

# 3. Create an envelope (draft)
envelope = client.envelopes.create(
    template_id=template["id"],
    title="NDA — Acme Corp",
    signers=[
        {"role_name": "Disclosing Party", "email": "alice@example.com", "name": "Alice Nguyen"},
        {"role_name": "Receiving Party",  "email": "bob@example.com",   "name": "Bob Smith"},
    ],
    variables={
        "effective_date": "2026-05-04",
        "party_a_name": "Smartshares Limited",
    },
    expires_in_days=14,
)

# 4. Send it — dispatches signer invite emails
client.envelopes.send(envelope["id"])

# 5. Check status
detail = client.envelopes.get(envelope["id"])
print(detail["status"])  # "sent", "in_progress", "completed", …

# 6. Download the executed PDF when complete
if detail["status"] == "completed":
    response = client.envelopes.get_signed_document(envelope["id"])
    with open("signed.pdf", "wb") as f:
        f.write(response.content)
```

## Async client

```python
import asyncio
from permissio import AsyncPermissio

async def main():
    async with AsyncPermissio(api_key="sk_live_…") as client:
        envelope = await client.envelopes.create(
            template_id="tpl_…",
            signers=[{"role_name": "Signer", "email": "a@b.com", "name": "Alice"}],
        )
        await client.envelopes.send(envelope["id"])

asyncio.run(main())
```

## Client options

```python
client = Permissio(
    api_key="sk_live_…",                        # required
    base_url="https://app.permissio.us/api",    # optional — default shown
    timeout=30.0,                               # optional — seconds, default 30
    http_client=httpx.Client(...),              # optional — custom httpx client
)
```

## Error handling

All API errors are raised as `PermissioApiError`:

```python
from permissio import Permissio, PermissioApiError

try:
    client.envelopes.send("env_…")
except PermissioApiError as err:
    print(err.code)       # e.g. "invalid_state"
    print(err.status)     # HTTP status, e.g. 409
    print(err.request_id) # include in support tickets
    print(err.details)    # additional structured info
```

### Common error codes

| Code | Status | Meaning |
|------|--------|---------|
| `unauthorized` | 401 | Invalid or missing API key |
| `forbidden` | 403 | Key lacks the required scope |
| `not_found` | 404 | Resource does not exist or belongs to another tenant |
| `invalid_state` | 409 | Operation not allowed in the envelope's current state |
| `idempotency_conflict` | 409 | Same idempotency key, different request body |
| `idempotency_in_progress` | 425 | Concurrent request with the same key is still in flight |
| `validation_error` | 422 | Request body failed validation |

## Idempotency

Write operations auto-generate a UUID as the `Idempotency-Key` header. Override to replay a specific request:

```python
import uuid
key = str(uuid.uuid4())
envelope = client.envelopes.create(template_id="tpl_…", signers=[…], idempotency_key=key)
# Safe to retry with the same key — server returns the same envelope:
envelope2 = client.envelopes.create(template_id="tpl_…", signers=[…], idempotency_key=key)
assert envelope["id"] == envelope2["id"]
```

## Webhooks

```python
from flask import Flask, request, abort
from permissio.namespaces import WebhooksNamespace

app = Flask(__name__)

@app.post("/webhooks/permissio")
def handle_webhook():
    if not WebhooksNamespace.verify_signature(
        request.data,
        request.headers.get("Permissio-Signature", ""),
        ENDPOINT_SECRET,
    ):
        abort(400)
    event = request.json
    if event["type"] == "envelope.completed":
        print(f"Envelope {event['data']['envelope']['id']} completed!")
    return "", 200
```

## Namespaces

| Namespace | Methods |
|-----------|---------|
| `client.envelopes` | `list()`, `create()`, `get()`, `send()`, `void()`, `get_signed_document()`, `get_certificate()` |
| `client.templates` | `list()`, `get()`, `create()`, `get_upload_url()` |
| `client.webhooks`  | `list()`, `create()`, `get()`, `verify_signature()` |

## Resources

- [Full API reference](https://docs.permissio.us)
- [Changelog](../../CHANGELOG.md)
- [Versioning & deprecation policy](../../docs/api-versioning.md)
- [PyPI package](https://pypi.org/project/permissio/)
