Skip to content

Python SDK

The Python SDK provides an async client for integrating with Subnoto’s API with Oak tunnel encryption and HTTP signature authentication.

Terminal window
pip install subnoto-api-client
import asyncio
from 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())
OptionTypeRequiredDescription
api_base_urlstrYesAPI base URL (e.g., https://enclave.subnoto.com)
access_keystrYesAPI access key from your team settings
secret_keystrYesAPI secret key (hex-encoded) from your team settings
unattestedboolNoUse unattested mode for development (default: False)
attester_keybytesNoPublic key for attestation verification
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"]
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"]
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 usage
recipients = [
{
"type": "manual",
"label": "customer",
"email": "[email protected]",
"firstname": "John",
"lastname": "Doe"
},
{
"type": "manual",
"label": "manager",
"email": "[email protected]",
"firstname": "Jane",
"lastname": "Smith"
}
]
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}")
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"]
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"]
import asyncio
from 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",
"email": "[email protected]",
"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())

The SDK includes generated API types for type-safe interactions:

from subnoto_api_client import SubnotoClient, SubnotoConfig
from subnoto_api_client.generated.api.utils import post_public_utils_whoami
from subnoto_api_client.generated.api.workspace import post_public_workspace_list
from subnoto_api_client.generated.api.envelope import post_public_envelope_list
from subnoto_api_client.generated.models.post_public_utils_whoami_body import PostPublicUtilsWhoamiBody
from 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())

For complete API documentation, see the OpenAPI specifications.