Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

permissio

Official Python SDK for the Permissio Partner API. Build document-signing workflows directly into your product.

Installation

pip install permissio

Requires Python 3.9+ and httpx.

Quick start

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

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

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:

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:

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

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

Metadata

Release files for permissio 0.1.0b1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for permissio 0.1.0b1
File Size Uploaded
permissio-0.1.0b1.tar.gz 120.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for permissio 0.1.0b1
File Interpreter ABI Platform
permissio-0.1.0b1-py3-none-any.whl Python 3 none any Details

Total release size: 136.1 kB

Release files / permissio-0.1.0b1.tar.gz

Download URL permissio-0.1.0b1.tar.gz
Size 120.9 kB
Tags Source
SHA-256 checksum
How to use checksums
43783e0be17d139de9b0b90d22e1b14db4ccb24b0b5729b0edceb6f9a27317e8
BLAKE2b-256 checksum
How to use checksums
e5acca8cc485e4c1bbdf6bbfdb2ba54c6503b0e7f5cefd9943c60d44f72eb4b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / permissio-0.1.0b1-py3-none-any.whl

Download URL permissio-0.1.0b1-py3-none-any.whl
Size 15.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f223a43b5330294d9aeca07e37fc1ae7206a901f0214c5537600d2355ffac4c
BLAKE2b-256 checksum
How to use checksums
311e2fffb5b2c58f38ccdb74be2c32a3266a9c7a93cd593420f549747c428087
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release history Release notifications | RSS feed

This release

0.1.0b1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page