Skip to content

Python SDK

The Python SDK provides both async and sync clients 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:
response = await client.post("/public/utils/whoami", json={})
print(f"User: {response.json()}")
response = await client.post("/public/workspace/list", json={})
print(f"Workspaces: {response.json()}")
if __name__ == "__main__":
asyncio.run(main())
from subnoto_api_client import SubnotoSyncClient, SubnotoConfig
config = SubnotoConfig(
api_base_url="https://enclave.subnoto.com",
access_key="your-access-key",
secret_key="your-secret-key-hex"
)
with SubnotoSyncClient(config) as client:
response = client.post("/public/utils/whoami", json={})
print(f"User: {response.json()}")
response = client.post("/public/workspace/list", json={})
print(f"Workspaces: {response.json()}")
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

All examples below use the async client. For the sync version, replace SubnotoClient with SubnotoSyncClient, async with with with, and remove async/await keywords.

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['title']} ({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={})
workspace_uuid = response.json()["workspaces"][0]["uuid"]
# 2. Get template
response = await client.post("/public/template/list", json={"page": 1})
template_uuid = response.json()["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())
from subnoto_api_client import SubnotoSyncClient, SubnotoConfig
config = SubnotoConfig(
api_base_url="https://enclave.subnoto.com",
access_key="your-access-key",
secret_key="your-secret-key-hex"
)
with SubnotoSyncClient(config) as client:
# 1. Get workspace
response = client.post("/public/workspace/list", json={})
workspace_uuid = response.json()["workspaces"][0]["uuid"]
# 2. Get template
response = client.post("/public/template/list", json={"page": 1})
template_uuid = response.json()["templates"][0]["uuid"]
# 3. Create envelope from template
response = 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
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!")

The SDK includes generated API types for type-safe interactions. Each generated endpoint module exposes both .asyncio() and .sync() methods.

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.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:
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)")
from subnoto_api_client import SubnotoSyncClient, 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.models.post_public_utils_whoami_body import PostPublicUtilsWhoamiBody
from subnoto_api_client.generated.models.post_public_workspace_list_body import PostPublicWorkspaceListBody
config = SubnotoConfig(
api_base_url="https://enclave.subnoto.com",
access_key="your-access-key",
secret_key="your-secret-key-hex"
)
with SubnotoSyncClient(config) as client:
response = post_public_utils_whoami.sync(
client=client.generated,
body=PostPublicUtilsWhoamiBody()
)
print(f"User info: {response.to_dict()}")
response = post_public_workspace_list.sync(
client=client.generated,
body=PostPublicWorkspaceListBody()
)
workspaces = response.to_dict().get('workspaces', [])
print(f"Found {len(workspaces)} workspace(s)")

For complete API documentation, see the OpenAPI specifications.