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.
Installation
Section intitulée « Installation »pip install subnoto-api-clientDémarrage rapide
Section intitulée « Démarrage rapide »Définissez vos identifiants comme variables d’environnement - SubnotoConfig() les récupère automatiquement :
export SUBNOTO_ACCESS_KEY="votre-clé-d-accès"export SUBNOTO_SECRET_KEY="votre-clé-secrète-hex"import asynciofrom 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())from subnoto_api_client import SubnotoSyncClient, SubnotoConfig
with SubnotoSyncClient(SubnotoConfig()) as client: response = client.post("/public/utils/whoami", json={}) print(f"Utilisateur : {response.json()}")
response = client.post("/public/workspace/list", json={}) print(f"Espaces de travail : {response.json()}")Configuration
Section intitulée « Configuration »Toutes les options sont facultatives. Les identifiants sont lus depuis les variables d’environnement si non fournis explicitement.
| Option | Type | Défaut | Description |
|---|---|---|---|
access_key | str | Variable SUBNOTO_ACCESS_KEY | Clé d’accès API depuis les paramètres de votre équipe |
secret_key | str | Variable SUBNOTO_SECRET_KEY | Clé 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",)Cas d’usage courants
Section intitulée « Cas d’usage courants »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.
Lister les espaces de travail
Section intitulée « Lister les espaces de travail »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"]Lister les enveloppes d’un espace de travail
Section intitulée « Lister les enveloppes d’un espace de travail »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"]Créer une enveloppe depuis un modèle
Section intitulée « Créer une enveloppe depuis un modèle »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", "firstname": "Jean", "lastname": "Dupont" }]Créer une enveloppe depuis un fichier
Section intitulée « Créer une enveloppe depuis un fichier »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 dataEnvoyer une enveloppe
Section intitulée « Envoyer une enveloppe »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}")Lister les modèles
Section intitulée « Lister les modèles »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"]Lister les contacts
Section intitulée « Lister les contacts »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 une enveloppe
Section intitulée « Récupérer une enveloppe »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 dataAjouter des destinataires
Section intitulée « Ajouter des destinataires »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", "firstname": "Jean", "lastname": "Dupont" } ] }) data = response.json()
for r in data.get("recipients", []): print(f" Ajouté : {r['firstname']} {r['lastname']} ({r['email']})") return dataAjouter des blocs
Section intitulée « Ajouter des blocs »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, }, { "type": "text", "page": "1", "x": 100, "y": 460, "width": 200, "height": 27, "text": "", "templatedText": "fullname", } ] }) 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.
Supprimer une enveloppe
Section intitulée « Supprimer une enveloppe »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")Exemple de workflow complet
Section intitulée « Exemple de workflow complet »import asynciofrom pathlib import Pathfrom 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", "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, }, { "type": "text", "page": "1", "x": 100, "y": 460, "width": 200, "height": 27, "text": "", "templatedText": "fullname", } ] })
# 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())Utilisation des types d’API générés
Section intitulée « Utilisation des types d’API générés »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, 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.models.post_public_utils_whoami_body import PostPublicUtilsWhoamiBodyfrom 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)")from subnoto_api_client import SubnotoSyncClient, 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.models.post_public_utils_whoami_body import PostPublicUtilsWhoamiBodyfrom subnoto_api_client.generated.models.post_public_workspace_list_body import PostPublicWorkspaceListBody
with SubnotoSyncClient(SubnotoConfig()) as client: response = post_public_utils_whoami.sync( client=client.generated, body=PostPublicUtilsWhoamiBody() ) print(f"Infos utilisateur : {response.to_dict()}")
response = post_public_workspace_list.sync( client=client.generated, body=PostPublicWorkspaceListBody() ) workspaces = response.to_dict().get('workspaces', []) print(f"{len(workspaces)} espace(s) de travail trouvé(s)")Référence API
Section intitulée « Référence API »Pour la documentation complète de l’API, consultez les spécifications OpenAPI.
- PyPI : subnoto-api-client
- Licence : Apache-2.0