Aller au contenu

SDK Python

Le SDK Python fournit des clients asynchrone et synchrone pour intégrer l’API Subnoto avec chiffrement tunnel Oak et authentification par signature HTTP.

Terminal window
pip install subnoto-api-client

Définissez vos identifiants comme variables d’environnement - SubnotoConfig() les récupère automatiquement :

Terminal window
export SUBNOTO_ACCESS_KEY="votre-clé-d-accès"
export SUBNOTO_SECRET_KEY="votre-clé-secrète-hex"
import asyncio
from subnoto_api_client import SubnotoClient, SubnotoConfig
async def main():
async with SubnotoClient(SubnotoConfig()) as client:
response = await client.post("/public/utils/whoami", json={})
print(f"Utilisateur : {response.json()}")
response = await client.post("/public/workspace/list", json={})
print(f"Espaces de travail : {response.json()}")
asyncio.run(main())

Toutes les options sont facultatives. Les identifiants sont lus depuis les variables d’environnement si non fournis explicitement.

OptionTypeDéfautDescription
access_keystrVariable SUBNOTO_ACCESS_KEYClé d’accès API depuis les paramètres de votre équipe
secret_keystrVariable SUBNOTO_SECRET_KEYClé secrète API (encodée en hex) depuis les paramètres

Les identifiants peuvent aussi être passés explicitement si les variables d’environnement ne sont pas pratiques :

config = SubnotoConfig(
access_key="votre-clé-d-accès",
secret_key="votre-clé-secrète-hex",
)

Tous les exemples ci-dessous utilisent le client asynchrone. Pour la version synchrone, remplacez SubnotoClient par SubnotoSyncClient, async with par with, et supprimez les mots-clés async/await.

async def list_workspaces(client):
response = await client.post("/public/workspace/list", json={})
data = response.json()
for workspace in data.get("workspaces", []):
print(f"Espace de travail : {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"Enveloppe : {envelope['title']} - Statut : {envelope['status']}")
return data["envelopes"]
async def create_envelope_from_template(client, workspace_uuid, template_uuid, recipients):
response = await client.post("/public/envelope/create-from-template", json={
"workspaceUuid": workspace_uuid,
"templateUuid": template_uuid,
"recipients": recipients
})
data = response.json()
print(f"Enveloppe créée : {data['envelopeUuid']}")
return data
recipients = [
{
"type": "manual",
"label": "customer",
"email": "[email protected]",
"firstname": "Jean",
"lastname": "Dupont"
}
]

Utilisez un envoi multipart pour créer une enveloppe directement depuis un PDF ou un document Word :

from pathlib import Path
async def create_envelope_from_file(client, workspace_uuid, file_path, title):
with open(file_path, "rb") as f:
file_buffer = f.read()
response = await client.post(
"/public/envelope/create-from-file",
data={
"workspaceUuid": workspace_uuid,
"envelopeTitle": title,
},
files={"file": (Path(file_path).name, file_buffer, "application/pdf")},
)
data = response.json()
print(f"Enveloppe créée : {data['envelopeUuid']}")
return data
async def send_envelope(client, workspace_uuid, envelope_uuid, custom_message=None):
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"Enveloppe {envelope_uuid} envoyée avec succès !")
else:
print(f"Échec de l'envoi : {response.text}")
async def list_templates(client):
response = await client.post("/public/template/list", json={"page": 1})
data = response.json()
for template in data.get("templates", []):
print(f"Modèle : {template['title']} ({template['uuid']})")
return data["templates"]
async def list_contacts(client, workspace_uuid):
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"]

Récupérer les détails d’une enveloppe, y compris les documents, blocs et destinataires.

async def get_envelope(client, envelope_uuid):
response = await client.post("/public/envelope/get", json={
"envelopeUuid": envelope_uuid
})
data = response.json()
print(f"Enveloppe : {data['title']} - Statut : {data['status']}")
for doc in data.get("documents", []):
print(f" Document : {doc['uuid']} ({doc['pageCount']} pages)")
return data

Ajouter des destinataires à une enveloppe en brouillon. Les destinataires peuvent être des saisies manuelles, des contacts existants ou des membres de l’espace de travail.

async def add_recipients(client, envelope_uuid):
response = await client.post("/public/envelope/add-recipients", json={
"envelopeUuid": envelope_uuid,
"recipients": [
{
"type": "manual",
"email": "[email protected]",
"firstname": "Jean",
"lastname": "Dupont"
}
]
})
data = response.json()
for r in data.get("recipients", []):
print(f" Ajouté : {r['firstname']} {r['lastname']} ({r['email']})")
return data

Ajouter des blocs de signature, texte, date ou image à un document. Les blocs doivent être ajoutés tant que l’enveloppe est au statut draft.

async def add_blocks(client, envelope_uuid, document_uuid):
response = await client.post("/public/envelope/add-blocks", json={
"envelopeUuid": envelope_uuid,
"documentUuid": document_uuid,
"blocks": [
{
"type": "signature",
"page": "1",
"x": 100,
"y": 500,
"recipientEmail": "[email protected]"
},
{
"type": "text",
"page": "1",
"x": 100,
"y": 460,
"width": 200,
"height": 27,
"text": "",
"templatedText": "fullname",
"recipientEmail": "[email protected]"
}
]
})
return response.json()

Blocs de texte dynamique : lorsque templatedText est défini sur un bloc texte, le champ text est automatiquement rempli à partir des données du destinataire au moment de la création. Valeurs disponibles :

  • "fullname" — prénom et nom du destinataire
  • "email" — adresse email du destinataire
  • "phone" — numéro de téléphone du destinataire

recipientEmail doit être défini et correspondre à un destinataire existant sur l’enveloppe pour que le texte dynamique soit résolu.

async def delete_envelope(client, envelope_uuid):
response = await client.post("/public/envelope/delete", json={
"envelopeUuid": envelope_uuid
})
if response.status_code == 200:
print(f"Enveloppe {envelope_uuid} supprimée")
import asyncio
from pathlib import Path
from subnoto_api_client import SubnotoClient, SubnotoConfig
async def create_and_send_envelope():
async with SubnotoClient(SubnotoConfig()) as client:
# 1. Créer l'enveloppe depuis un fichier (espace de travail par défaut)
with open("contrat.pdf", "rb") as f:
file_buffer = f.read()
response = await client.post(
"/public/envelope/create-from-file",
data={"envelopeTitle": "Contrat de service"},
files={"file": ("contrat.pdf", file_buffer, "application/pdf")},
)
result = response.json()
envelope_uuid = result["envelopeUuid"]
# 2. Récupérer l'UUID du document
response = await client.post("/public/envelope/get", json={
"envelopeUuid": envelope_uuid
})
document_uuid = response.json()["documents"][0]["uuid"]
# 3. Ajouter les destinataires
await client.post("/public/envelope/add-recipients", json={
"envelopeUuid": envelope_uuid,
"recipients": [{
"type": "manual",
"email": "[email protected]",
"firstname": "Marie",
"lastname": "Martin"
}]
})
# 4. Ajouter les blocs de signature et nom auto-rempli
await client.post("/public/envelope/add-blocks", json={
"envelopeUuid": envelope_uuid,
"documentUuid": document_uuid,
"blocks": [
{
"type": "signature",
"page": "1",
"x": 100,
"y": 500,
"recipientEmail": "[email protected]"
},
{
"type": "text",
"page": "1",
"x": 100,
"y": 460,
"width": 200,
"height": 27,
"text": "",
"templatedText": "fullname",
"recipientEmail": "[email protected]"
}
]
})
# 5. Envoyer l'enveloppe
await client.post("/public/envelope/send", json={
"envelopeUuid": envelope_uuid,
"customInvitationMessage": "Merci de consulter et signer ce document."
})
print(f"Enveloppe {envelope_uuid} créée et envoyée !")
asyncio.run(create_and_send_envelope())

Le SDK inclut des types d’API générés pour des interactions type-safe. Chaque module d’endpoint généré expose les méthodes .asyncio() et .sync().

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():
async with SubnotoClient(SubnotoConfig()) as client:
response = await post_public_utils_whoami.asyncio(
client=client.generated,
body=PostPublicUtilsWhoamiBody()
)
print(f"Infos utilisateur : {response.to_dict()}")
response = await post_public_workspace_list.asyncio(
client=client.generated,
body=PostPublicWorkspaceListBody()
)
workspaces = response.to_dict().get('workspaces', [])
print(f"{len(workspaces)} espace(s) de travail trouvé(s)")

Pour la documentation complète de l’API, consultez les spécifications OpenAPI.