Python SDK
The Python SDK provides an async client for integrating with Subnoto’s API with Oak tunnel encryption and HTTP signature authentication.
Installation
Section titled “Installation”pip install subnoto-api-clientQuick Start
Section titled “Quick Start”import asynciofrom subnoto_api_client import SubnotoClient, SubnotoConfig
async def main(): config = SubnotoConfig( api_base_url="https://enclave.subnoto.com", access_key="your-access-key", secret_key="your-secret-key-hex" )
async with SubnotoClient(config) as client: # Get current user info response = await client.post("/public/utils/whoami", json={}) user_info = response.json() print(f"User: {user_info}")
# List workspaces response = await client.post("/public/workspace/list", json={}) workspaces = response.json() print(f"Workspaces: {workspaces}")
if __name__ == "__main__": asyncio.run(main())Configuration
Section titled “Configuration”| Option | Type | Required | Description |
|---|---|---|---|
api_base_url | str | Yes | API base URL (e.g., https://enclave.subnoto.com) |
access_key | str | Yes | API access key from your team settings |
secret_key | str | Yes | API secret key (hex-encoded) from your team settings |
unattested | bool | No | Use unattested mode for development (default: False) |
attester_key | bytes | No | Public key for attestation verification |
Common Use Cases
Section titled “Common Use Cases”List Workspaces
Section titled “List Workspaces”async def list_workspaces(client): response = await client.post("/public/workspace/list", json={}) data = response.json()
for workspace in data.get("workspaces", []): print(f"Workspace: {workspace['name']} ({workspace['uuid']})")
return data["workspaces"]List Envelopes in a Workspace
Section titled “List Envelopes in a Workspace”async def list_envelopes(client, workspace_uuid): response = await client.post("/public/envelope/list", json={ "workspaceUuid": workspace_uuid, "page": 1 }) data = response.json()
for envelope in data.get("envelopes", []): print(f"Envelope: {envelope['title']} - Status: {envelope['status']}")
return data["envelopes"]Create an Envelope from Template
Section titled “Create an Envelope from Template”async def create_envelope_from_template(client, workspace_uuid, template_uuid, recipients): """ Create an envelope from a pre-configured template. Recipients must include labels that match the template's recipient labels. """ response = await client.post("/public/envelope/create-from-template", json={ "workspaceUuid": workspace_uuid, "templateUuid": template_uuid, "recipients": recipients }) data = response.json()
print(f"Created envelope: {data['envelopeUuid']}") return data
# Example usagerecipients = [ { "type": "manual", "label": "customer", "firstname": "John", "lastname": "Doe" }, { "type": "manual", "label": "manager", "firstname": "Jane", "lastname": "Smith" }]Send an Envelope
Section titled “Send an Envelope”async def send_envelope(client, workspace_uuid, envelope_uuid, custom_message=None): """Send an envelope to all recipients.""" body = { "workspaceUuid": workspace_uuid, "envelopeUuid": envelope_uuid }
if custom_message: body["customInvitationMessage"] = custom_message
response = await client.post("/public/envelope/send", json=body)
if response.status_code == 200: print(f"Envelope {envelope_uuid} sent successfully!") else: print(f"Failed to send envelope: {response.text}")List Templates
Section titled “List Templates”async def list_templates(client): """List all available templates.""" response = await client.post("/public/template/list", json={"page": 1}) data = response.json()
for template in data.get("templates", []): print(f"Template: {template['name']} ({template['uuid']})")
return data["templates"]List Contacts
Section titled “List Contacts”async def list_contacts(client, workspace_uuid): """List contacts in a workspace.""" response = await client.post("/public/contact/list", json={ "workspaceUuid": workspace_uuid }) data = response.json()
for contact in data.get("contacts", []): print(f"Contact: {contact['firstname']} {contact['lastname']} ({contact['email']})")
return data["contacts"]Full Workflow Example
Section titled “Full Workflow Example”import asynciofrom subnoto_api_client import SubnotoClient, SubnotoConfig
async def create_and_send_envelope(): config = SubnotoConfig( api_base_url="https://enclave.subnoto.com", access_key="your-access-key", secret_key="your-secret-key-hex" )
async with SubnotoClient(config) as client: # 1. Get workspace response = await client.post("/public/workspace/list", json={}) workspaces = response.json()["workspaces"] workspace_uuid = workspaces[0]["uuid"]
# 2. Get template response = await client.post("/public/template/list", json={"page": 1}) templates = response.json()["templates"] template_uuid = templates[0]["uuid"]
# 3. Create envelope from template response = await client.post("/public/envelope/create-from-template", json={ "workspaceUuid": workspace_uuid, "templateUuid": template_uuid, "recipients": [ { "type": "manual", "label": "signer", "firstname": "John", "lastname": "Doe" } ] }) envelope_uuid = response.json()["envelopeUuid"]
# 4. Send the envelope await client.post("/public/envelope/send", json={ "workspaceUuid": workspace_uuid, "envelopeUuid": envelope_uuid, "customInvitationMessage": "Please review and sign this document." })
print(f"Envelope {envelope_uuid} created and sent!")
if __name__ == "__main__": asyncio.run(create_and_send_envelope())Using Generated API Types
Section titled “Using Generated API Types”The SDK includes generated API types for type-safe interactions:
from subnoto_api_client import SubnotoClient, SubnotoConfigfrom subnoto_api_client.generated.api.utils import post_public_utils_whoamifrom subnoto_api_client.generated.api.workspace import post_public_workspace_listfrom subnoto_api_client.generated.api.envelope import post_public_envelope_listfrom subnoto_api_client.generated.models.post_public_utils_whoami_body import PostPublicUtilsWhoamiBodyfrom subnoto_api_client.generated.models.post_public_workspace_list_body import PostPublicWorkspaceListBody
async def main(): config = SubnotoConfig( api_base_url="https://enclave.subnoto.com", access_key="your-access-key", secret_key="your-secret-key-hex" )
async with SubnotoClient(config) as client: # Use generated client for type-safe calls response = await post_public_utils_whoami.asyncio( client=client.generated, body=PostPublicUtilsWhoamiBody() ) print(f"User info: {response.to_dict()}")
response = await post_public_workspace_list.asyncio( client=client.generated, body=PostPublicWorkspaceListBody() ) workspaces = response.to_dict().get('workspaces', []) print(f"Found {len(workspaces)} workspace(s)")
if __name__ == "__main__": asyncio.run(main())API Reference
Section titled “API Reference”For complete API documentation, see the OpenAPI specifications.
Package
Section titled “Package”- PyPI: subnoto-api-client
- License: Apache-2.0