Secure Exchanges Python SDK
English | Français
Python SDK for the Secure Exchanges API: secure file transfer, end-to-end encrypted messaging, and digital signing of PDF documents.
The SDK covers the entire protocol: post-quantum handshake, end-to-end encryption of messages and files, electronic signatures with PKI certification, and message logs.
Table of contents
- Installation
- Prerequisites
- Credentials and configuration
- Security
- SDK architecture
- Usage guide
- API reference
- Data models
- Support
- License
Installation
pip install secure-exchanges-sdk
This installs everything needed for sending messages, attachments, logs, and phone number validation.
Electronic signature on PDF (signature extra)
Defining signature zones (ZoneBuilder) and PDF certification
(PkiFileHelper) require two additional dependencies, pypdf and
playwright, deliberately not installed by default: playwright downloads a
browser of roughly 150 MB:
pip install "secure-exchanges-sdk[signature]"
playwright install chromium
Prerequisites
To use the SDK, you need:
- Python 3.10+
- A serial number (
serial) : the UUID of your licence - An API user ID (
api_user) : the UUID of the API user - An API password (
api_password) : the UUID of the API password
Credentials and configuration
Where to find your credentials
The 3 required credentials (serial, api_user, api_password) are UUIDs (GUIDs) that you obtain from your Secure Exchanges administration portal when creating your API licence.
| Credential | Description | Example |
|---|---|---|
serial |
Serial number of your licence | UUID("d17ca972-5f70-4961-bac4-98e6b91b1dc4") |
api_user |
API user identifier | UUID("0fa0cf77-4ca5-4406-8623-1ed0ffd47290") |
api_password |
API user password | UUID("4bfeabdf-c498-448a-9255-1e17c3ef8c0b") |
Configuration
SettingsHelper selects the environment and returns its endpoints, nothing
else. The SDK stores no credentials and never reads them from the process
environment: the serial, the API user and the API password are yours, and are
passed explicitly to every call.
from secure_exchanges_sdk.client import SecureExchangesClient, SEMSClient
from secure_exchanges_sdk.helpers.settings_helper import SettingsHelper
cfg = SettingsHelper.configure_production()
client = SecureExchangesClient(cfg['api_endpoint'])
sems_client = SEMSClient(cfg['sems_endpoint'])
# load_my_credentials() is your own function: it returns the three UUID objects
# of your licence (uuid.UUID, not str). See "Protecting your credentials"
# below for where to keep them.
serial, api_user, api_password = load_my_credentials()
| Function | Environment | Endpoints |
|---|---|---|
configure_production() |
production | www.secure-exchanges.com |
configure_preview() |
preview (test) | preview.secure-exchanges.com |
Each one returns a dict with api_endpoint, sems_endpoint, file_handler,
file_upload_handler and environment.
Preview and production credentials are different: a production serial will not work in preview, and vice versa.
Protecting your credentials
These three UUIDs are the equivalent of a password on your Secure Exchanges account: whoever holds them can send, read and delete messages in your name, and the usage is billed to you. How they are stored is entirely your decision, and your responsibility.
- Never commit them. Keep them out of the repository, and check the history
too:
git log -S <serial>finds a secret committed once and removed later. A secret that reached a remote is compromised: rotate it, don't just delete the line. - Never hard-code them in source. They end up in stack traces, in bug reports, in the packages you ship, and in every fork of the code.
- Prefer a secret manager. Encrypted at rest, access audited, rotation possible without a redeploy.
- If you keep them in a file, encrypt it or lock it down. Outside the web
root, owned by the service account, permissions
0400, and excluded from your backups or encrypted inside them. - Beware of the process environment. Environment variables are readable
from
/proc/<pid>/environby anything running under the same user, they show up in crash dumps and in most error reporters. Load the credentials at the moment you need them rather than exporting them for the whole process lifetime. - Keep them out of your logs. Exclude them explicitly from your error handler, from your crash reporter and from request dumps, which capture environment and local variables by default.
- Rotate them from the administration portal the moment you suspect an exposure: a laptop lost, a log shipped to a third party, a developer leaving.
Security
- End-to-end encryption: the content (message body and files) is encrypted locally, with keys generated on your machine and never sent to the server: the server only stores and relays encrypted data.
- Post-quantum key exchange: ML-KEM-1024 (FIPS 203), resistant to quantum computer attacks, signed with ML-DSA-87 (FIPS 204).
- AES-256 encryption of the content and of all exchanges with the server.
- Interception protection: any man-in-the-middle (MITM) attack attempt causes the connection to fail.
- Nothing to manage: the SDK automatically applies the entire protocol on every call: you never have to handle any cryptographic primitives.
SDK architecture
Overview of the main modules. In practice, you will mostly use the helpers, which orchestrate the full protocol for you:
| Module | Role |
|---|---|
client/ |
HTTP clients: SecureExchangesClient (main API), SEMSClient (email delivery) |
helpers/message_helper.py |
Sending, reading, deleting messages, reply envelopes |
helpers/handshake_helper.py |
Post-quantum handshake (ML-KEM-1024 + ML-DSA-87) |
helpers/post_quantum_crypto_helper.py |
Post-quantum primitives for the handshake |
helpers/crypto_helper.py |
Low-level symmetric/RSA cryptography (AES-256, SHA-512, .NET GUIDs) |
helpers/logs_helper.py |
Retrieval of message logs |
helpers/sign_helper.py, helpers/zone_builder.py |
Electronic signature zones on PDF |
helpers/pki_file_helper.py |
PKI certification of PDFs (headless browser) |
helpers/file_helper.py |
Encrypted file upload/download (chunked, parallel) |
helpers/settings_helper.py |
Configuration (environments, endpoints) |
helpers/contact_helper.py, licence_helper.py |
Contacts, licence validation |
helpers/email_helper.py, phone_helper.py, mime_helper.py |
Validations (email, phone, MIME types) |
models/ |
Data models: responses (answer/), entities (entity/), enumerations (enum/), transport, JSON |
callback/ |
Models for notification callbacks |
Usage guide
All the examples below assume the following setup (see Configuration):
from secure_exchanges_sdk.client import SecureExchangesClient, SEMSClient
from secure_exchanges_sdk.helpers.settings_helper import SettingsHelper
cfg = SettingsHelper.configure_production()
client = SecureExchangesClient(cfg['api_endpoint'])
sems_client = SEMSClient(cfg['sems_endpoint'])
# Your own function: it returns the three UUID objects of your licence.
serial, api_user, api_password = load_my_credentials()
Sending a simple message
from secure_exchanges_sdk.helpers.message_helper import MessageHelper
from secure_exchanges_sdk.models.entity.recipient_info import RecipientInfo
recipients = [
RecipientInfo(email="recipient@example.com")
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Hello, here is a secure message.</p>",
subject="Confidential message",
culture_id="en-US"
)
if answer.status == 200:
print("Message sent successfully!")
for ra in answer.recipients_answer:
if ra.answer and ra.answer.url:
print(f" URL: {ra.answer.url}")
else:
print(f"Error {answer.status}: {answer.data}")
Sending with password and SMS code (2FA)
from secure_exchanges_sdk.models.enum.send_method_enum import SendMethodEnum
recipients = [
RecipientInfo(email="user@example.com", phone="+15145551234")
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Confidential document attached.</p>",
subject="Protected document",
password="SecretPassword123",
send_method=SendMethodEnum.EMAIL_WITH_SMS_CODE, # link by email, code by SMS
culture_id="en-US",
maximum_open_time=3, # Maximum number of opens (1-99)
minutes_expiration=1440 # Expiration in minutes (1440 = 24h)
)
SendMethodEnum values:
| Value | Description |
|---|---|
ONLY_EMAIL (0) |
Link sent by email only (default) |
SMS_ONLY (1) |
Link sent by SMS only |
SMS_WITH_EMAIL_CODE (2) |
Link by SMS, opening code by email |
EMAIL_WITH_SMS_CODE (3) |
Link by email, opening code by SMS |
Password protection (
password) is independent of the delivery channel and can be combined with anysend_methodvalue.
Sending with attachments
# From disk
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>See attached files.</p>",
subject="Secure files",
files_path=["/path/to/document.pdf", "/path/to/image.png"]
)
# From memory (bytes)
pdf_bytes = open("/path/to/report.pdf", "rb").read()
csv_bytes = open("/path/to/data.csv", "rb").read()
files_in_memory = [
{"binary": pdf_bytes, "file_name": "report.pdf"},
{"binary": csv_bytes, "file_name": "data.csv"}
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Report and data attached.</p>",
subject="Monthly report",
files_list=files_in_memory
)
Sending with PKI certification
PKI certification applies a digital certificate to a PDF before sending it for signature. The process uses a headless browser (Playwright, signature extra). Signature zones are defined with ZoneBuilder, which reads the actual dimensions of the PDF pages:
import asyncio
from secure_exchanges_sdk.helpers.crypto_helper import CryptoHelper
from secure_exchanges_sdk.helpers.zone_builder import ZoneBuilder
from secure_exchanges_sdk.helpers.sign_helper import SignHelper
from secure_exchanges_sdk.helpers.pki_file_helper import PkiFileHelper, CertifyPdfArgs
from secure_exchanges_sdk.models.entity.sign_zone_definition import SignZoneDefinition
from secure_exchanges_sdk.models.transport.file_zone_definition import FileZoneDefinition
from secure_exchanges_sdk.models.transport.recipient_zone_definition import RecipientZoneDefinition
# 1. Read the PDF and compute its SHA512
pdf_path = "contract.pdf"
with open(pdf_path, "rb") as f:
pdf_bytes = f.read()
sha512 = CryptoHelper.get_sha512_hash_of_bytes(pdf_bytes)
# 2. Define the signature zones with ZoneBuilder
with ZoneBuilder(pdf_path, is_pki=True) as zone_builder:
zones = [
# Signature zone on page 1
zone_builder.create_field_sign_zone(
page=1, field_name="signature1",
x=60, y=400, width=200, height=50
),
# Date zone filled automatically at signing time
zone_builder.create_field_date_sign_zone(
page=1, field_name="date1",
x=60, y=500, width=100, height=25, font_size=12
),
]
# 3. Associate the zones with the recipient (file referenced by its SHA512)
recipient_zones = [
RecipientZoneDefinition(
email="signer@example.com",
phone=None,
zones_def_by_file=[
FileZoneDefinition(
unique_name=sha512,
do_not_encrypt_pdf=False,
do_not_append_certificate_to_file=False,
is_pki_file=True,
zones_def=SignZoneDefinition(mode="define", zones=zones)
)
]
)
]
# 4. Get the certification token
cert_response = SignHelper.get_certification_token(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
original_hash=sha512,
culture_id="en-US",
token_type="CertifyDocument"
)
cert_data = cert_response["certification_data"]
# 5. Certify the PDF via headless browser
certify_args = CertifyPdfArgs(
file_bytes=pdf_bytes,
file_name="contract.pdf",
recipients=["signer@example.com"],
certify_data=cert_data,
detect_existing_fields=True,
recipient_zone_definitions=recipient_zones
)
async def certify():
async with PkiFileHelper(is_preview=False, culture="en-US") as helper:
return await helper.certify_pki_pdf(certify_args)
certified = asyncio.run(certify())
# 6. Send the certified PDF
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=[RecipientInfo(email="signer@example.com")],
message="<p>Please sign this certified document.</p>",
subject="PKI document to sign",
certified_pdfs=[certified],
owner_dont_need_to_sign=True,
sems_client=sems_client
)
A complete, runnable example, including the signature options (SignOptions: signature mode restriction, requesting a file in return) and the callback parameters (contextual keys), can be found in example_pki_with_signature_options.py at the root of pythonSDK/.
Retrieving a message
# Parse a Secure Exchanges link
link = "https://www.secure-exchanges.com/message.aspx?msgid=xxx&sems=yyy&cpart=zzz"
msg_params = MessageHelper.get_secure_exchanges_message_from_link(link)
# Retrieve and decrypt the message
response = MessageHelper.get_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
msg_params=msg_params,
password="MyPassword" # if protected
)
Note: each read consumes one of the message's allowed opens (
maximum_open_time).
Message logs
Track the lifecycle of your messages (sending, opens, signatures):
from datetime import datetime, timedelta
from uuid import UUID
from secure_exchanges_sdk.helpers.logs_helper import LogsHelper
# All logs from the last 60 days
logs_response = LogsHelper.get_logs(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
from_date=datetime.now() - timedelta(days=60),
to_date=datetime.now()
)
# The log of a specific message (by message_id OR tracking_id)
log_response = LogsHelper.get_log(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
tracking_id=UUID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
)
Deleting a message
from uuid import UUID
success = MessageHelper.delete_message_by_tracking_id(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
tracking_id=UUID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
)
Reply envelopes
Envelopes let a recipient reply to you securely:
# Single envelope (one recipient)
env_response = MessageHelper.get_enveloppe(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
subject="Send me your documents",
destination="recipient@example.com",
culture_id="en-US",
reply_expiration_hours=48,
maximum_reply_open_time=3,
reply_to_api=True,
authorized_extensions=[".pdf", ".docx"]
)
if env_response.url:
print(f"Envelope URL: {env_response.url}")
# Multiple envelopes
env_responses = MessageHelper.get_envelopes(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
subject="Required documents",
recipients=[
{"Email": "user1@example.com"},
{"Email": "user2@example.com"}
]
)
API reference
MessageHelper
Static class for sending and receiving messages.
| Method | Description |
|---|---|
multi_recipient_message(api_client, serial, api_user, api_password, recipients, message, subject, ...) |
Sends a message to multiple recipients |
get_message(api_client, serial, api_user, api_password, msg_params, password=None, digit_code=None, sems_client=None) |
Retrieves and decrypts a message |
delete_message_by_tracking_id(api_client, serial, api_user, api_password, tracking_id, ...) |
Deletes a message by tracking ID |
get_enveloppe(api_client, serial, api_user, api_password, subject, destination, ...) |
Creates a reply envelope |
get_envelopes(api_client, serial, api_user, api_password, subject, recipients, ...) |
Creates multiple envelopes |
get_secure_exchanges_message_from_link(link) |
Parses an SE link into parameters |
send_trace(api_client, trace_content) |
Sends a support trace |
Parameters of multi_recipient_message
| Parameter | Type | Default | Description |
|---|---|---|---|
api_client |
SecureExchangesClient |
required | API client |
serial |
UUID |
required | Serial number |
api_user |
UUID |
required | API user ID |
api_password |
UUID |
required | API password |
recipients |
List[RecipientInfo] |
required | Recipients |
message |
str |
required | HTML content of the message |
subject |
str |
required | Message subject |
password |
str |
None |
Protection password |
files_list |
List[dict] |
None |
In-memory files ({"binary": bytes, "file_name": str}) |
files_path |
List[str] |
None |
Paths of files on disk |
send_method |
SendMethodEnum |
ONLY_EMAIL |
Delivery channel (see the SendMethodEnum table above) |
get_back_html |
bool |
True |
True=you send the email, False=SEMS sends it |
show_subject |
bool |
True |
Show the subject in the notification |
get_notify |
bool |
True |
Notify on open |
culture_id |
str |
"en-US" |
Language ("fr-CA", "en-US") |
maximum_open_time |
int |
1 |
Maximum number of opens (1-99) |
minutes_expiration |
int |
10080 |
Expiration in minutes (default: 7 days) |
create_message_copy |
bool |
False |
Copy for the sender |
name |
str |
"Secure Exchanges" |
Sender name |
callback_parameters |
str |
None |
Free-form parameters (JSON) returned in notification callbacks |
reply_options |
dict |
None |
Recipient reply options (see below) |
owner_dont_need_to_sign |
bool |
True |
The sender does not sign |
certified_pdfs |
List[CertifiedPdfContainer] |
None |
PKI-certified PDFs |
sign_options |
SignOptions |
None |
Signature options: mode restriction, CC/BCC recipients, upload options |
sems_client |
SEMSClient |
None |
SEMS client (created automatically if omitted) |
reply_options is a dictionary (PascalCase keys, matching the API) that
controls what the recipient can do in reply:
from secure_exchanges_sdk.models.enum.reply_file_upload_mode import ReplyFileUploadMode
reply_options = {
"UploadMode": int(ReplyFileUploadMode.UPLOAD_MANDATORY), # NO_UPLOAD, UPLOAD_OPTIONAL, UPLOAD_MANDATORY
"AuthorizedExtensions": [".jpg", ".png", ".pdf"],
"Messages": [
{"CultureID": "fr-CA", "Message": "Veuillez joindre votre document."},
{"CultureID": "en-CA", "Message": "Please attach your document."},
],
"NoEditor": False, # disable the reply text editor
"NoReply": False, # disallow any reply
}
sign_options (SignOptions, in models/json_models/sign_options.py)
provides, for a signature send: signature_restriction
(SignatureModeRestriction), cc_recipients / bcc_recipients
(carbon-copy recipients, non-signers) and upload_file_options.
LogsHelper
Retrieval of message logs (sends, opens, activities).
| Method | Description |
|---|---|
get_logs(api_client, serial, api_user, api_password, from_date, to_date, user_log_serial=None) |
All logs over a date range (datetime) → GetLogsResponse |
get_log(api_client, serial, api_user, api_password, message_id=None, tracking_id=None, user_log_serial=None) |
Log of a specific message: provide message_id or tracking_id → GetLogResponse |
SignHelper
Management of digital signature zones on PDFs.
| Method | Description |
|---|---|
add_file_zone_def_to_recipient_index(recipient_index, template_zones, sha512, recipients_match) |
Converts templates into zone definitions |
convert_recipient_index_to_list(recipient_index) |
Converts the index into a list for multi_recipient_message |
concat_recipient_zone_definition_lists(list1, list2) |
Merges two lists of zone definitions |
validate_all_recipients_have_zones(files_to_sign, recipients, recipients_zone_def) |
Checks that all recipients have zones |
validate_document_signature_integrity(api_client, file_sha512) |
Validates the integrity of a signed document |
get_certification_token(api_client, serial, api_user, api_password, original_hash, culture_id, ...) |
Obtains a PKI certification token |
PkiFileHelper
PKI certification of PDFs via headless browser (Playwright, signature extra).
# Asynchronous (recommended)
async with PkiFileHelper(is_preview=True, culture="en-US") as helper:
result = await helper.certify_pki_pdf(args)
# Synchronous
helper = PkiFileHelper(is_preview=True)
result = helper.certify_pki_pdf_sync(args)
helper.close_sync()
CertifyPdfArgs
| Property | Type | Description |
|---|---|---|
file_bytes |
bytes |
Binary content of the PDF |
file_name |
str |
File name |
recipients |
List[str] |
Recipient email addresses |
certify_data |
dict |
Certification token (from get_certification_token) |
detect_existing_fields |
bool |
Detect existing fields (default: True) |
recipient_zone_definitions |
List[RecipientZoneDefinition] |
Predefined zones |
define_recipients |
Callable |
Callback for distributing zones among recipients |
CertifiedPdfContainer
| Property | Type | Description |
|---|---|---|
file_bytes |
bytes |
Certified PDF |
file_name |
str |
File name |
sign_file_def |
dict |
Signature definition (SHA512, IsPKIFile, etc.) |
recipient_zone_definitions |
List[RecipientZoneDefinition] |
Zones updated with the new SHA512 |
ZoneBuilder
Builds signature zones from a PDF (helpers/zone_builder.py,
signature extra). The builder reads the actual dimensions of the PDF pages
and computes the coordinates expected by the server.
from secure_exchanges_sdk.helpers.zone_builder import ZoneBuilder
with ZoneBuilder(pdf_path, is_pki=True) as builder:
zone = builder.create_field_sign_zone(
page=1, field_name="signature1",
x=60, y=400, width=200, height=50
)
Zone types: signature (create_field_sign_zone), signature date
(create_field_date_sign_zone), initials, text, number, date, checkbox,
radio buttons, text area, option list, dropdown list.
CryptoHelper
Low-level cryptographic functions (normally used indirectly through the helpers).
| Category | Methods |
|---|---|
| AES-256-CBC | encrypt_string_to_bytes, decrypt_string_from_bytes, encrypt_binary, decrypt_binary_from_bytes, encrypt_string_to_b64, decrypt_string_from_base64, encrypt_file, decrypt_file |
| RSA | create_new_private_key, get_public_key_from_private_key, encrypt_rsa_content, decrypt_rsa_content |
| Hashing | get_sha512_hash_of_bytes, get_sha512_hash_of_string, get_sha256_hash_of_bytes, get_sha512_of_file |
| .NET GUIDs | guid_to_bytes_le, bytes_le_to_guid |
| Keys | generate_aes_keys, generate_secure_random_byte_array |
| Utilities | alter_binary, bytes_xor, concat_byte_arrays, hex_to_byte_array |
Data models
RecipientInfo
RecipientInfo(
email="user@example.com",
phone="+15145551234" # Optional, enables SMS 2FA
)
SignZoneDetails
Defines a signature zone on a PDF. In practice, you do not instantiate
SignZoneDetails yourself: zones are created via
ZoneBuilder, which computes the coordinates for you.
SignZoneDetails(
type="sign", # "sign", "initial", "stamp", "text", "checkbox"
page=1, # Page number (1-indexed)
left=100, # X position (pixels)
top=400, # Y position (pixels)
width=200, # Width (pixels)
height=80, # Height (pixels)
page_height=792, # Page height
canvas_width=612, # Canvas width
canvas_height=792, # Canvas height
rotate_degree=0, # Rotation (0, 90, 180, 270)
default_value=None # JSON string with field metadata (required for PKI)
)
RecipientZoneDefinition
Associates signature zones with a recipient for one or more files.
RecipientZoneDefinition(
email="signer@example.com",
phone=None,
zones_def_by_file=[
FileZoneDefinition(
unique_name=sha512, # SHA512 of the file
do_not_encrypt_pdf=False,
do_not_append_certificate_to_file=False,
is_pki_file=True, # PKI certification
zones_def=SignZoneDefinition(
mode="define",
zones=[...]
)
)
]
)
MultiRecipientAnswer
Response of multi_recipient_message:
| Property | Type | Description |
|---|---|---|
status |
int |
Status code (200=success) |
data |
str |
Descriptive message |
recipients_answer |
List[RecipientAnswer] |
Answers per recipient |
Each RecipientAnswer contains a SendMessageAnswer with url (the link to send to the recipient).
Support
For any questions or issues, contact supportdev@secure-exchanges.info or visit secure-exchanges.com. Product documentation: help.secure-exchanges.com.
License
Licensed under the Apache License, Version 2.0. Full text at
https://www.apache.org/licenses/LICENSE-2.0. The copyright notice is in the
NOTICE file.
Using the SDK also requires a Secure Exchanges licence (serial, API user and API password) obtained from your administration portal. The Apache licence covers this source code, not access to the service.
Secure Exchanges Python SDK (version française)
English | Français
SDK Python pour l'API Secure Exchanges : transfert de fichiers sécurisé, messagerie chiffrée de bout en bout et signature numérique de documents PDF.
Le SDK prend en charge l'intégralité du protocole : handshake post-quantique, chiffrement bout-en-bout des messages et des fichiers, signatures électroniques avec certification PKI et journaux de messages.
Table des matières
- Installation
- Prérequis
- Identifiants et configuration
- Sécurité
- Architecture du SDK
- Guide d'utilisation
- Référence API
- Modèles de données
- Support
- Licence
Installation
pip install secure-exchanges-sdk
Cela installe tout le nécessaire pour l'envoi de messages, les pièces jointes, les journaux et la validation des numéros de téléphone.
Signature électronique sur PDF (extra signature)
La définition de zones de signature (ZoneBuilder) et la certification PDF
(PkiFileHelper) demandent deux dépendances supplémentaires, pypdf et
playwright, volontairement non installées par défaut : playwright
télécharge un navigateur d'environ 150 Mo :
pip install "secure-exchanges-sdk[signature]"
playwright install chromium
Prérequis
Pour utiliser le SDK, vous devez disposer de :
- Python 3.10+
- Un numéro de série (
serial) : UUID de votre licence - Un identifiant API (
api_user) : UUID de l'utilisateur API - Un mot de passe API (
api_password) : UUID du mot de passe API
Identifiants et configuration
Où trouver vos identifiants
Les 3 identifiants nécessaires (serial, api_user, api_password) sont des UUID (GUIDs) que vous obtenez dans votre portail d'administration Secure Exchanges lors de la création de votre licence API.
| Identifiant | Description | Exemple |
|---|---|---|
serial |
Numéro de série de votre licence | UUID("d17ca972-5f70-4961-bac4-98e6b91b1dc4") |
api_user |
Identifiant de l'utilisateur API | UUID("0fa0cf77-4ca5-4406-8623-1ed0ffd47290") |
api_password |
Mot de passe de l'utilisateur API | UUID("4bfeabdf-c498-448a-9255-1e17c3ef8c0b") |
Configuration
SettingsHelper sélectionne l'environnement et retourne ses endpoints, rien
d'autre. Le SDK ne stocke aucun identifiant et ne va jamais les chercher dans
l'environnement du processus : le serial, l'utilisateur et le mot de passe API
vous appartiennent, et sont passés explicitement à chaque appel.
from secure_exchanges_sdk.client import SecureExchangesClient, SEMSClient
from secure_exchanges_sdk.helpers.settings_helper import SettingsHelper
cfg = SettingsHelper.configure_production()
client = SecureExchangesClient(cfg['api_endpoint'])
sems_client = SEMSClient(cfg['sems_endpoint'])
# charger_mes_identifiants() est votre propre fonction : elle retourne les trois UUID
# de votre licence (uuid.UUID, pas str). Voir « Protéger vos identifiants »
# ci-dessous pour savoir où les conserver.
serial, api_user, api_password = charger_mes_identifiants()
| Fonction | Environnement | Endpoints |
|---|---|---|
configure_production() |
production | www.secure-exchanges.com |
configure_preview() |
preview (test) | preview.secure-exchanges.com |
Chacune retourne un dictionnaire avec api_endpoint, sems_endpoint,
file_handler, file_upload_handler et environment.
Vos identifiants preview et production sont différents : un serial de production ne fonctionnera pas en preview, et inversement.
Protéger vos identifiants
Ces trois UUID valent un mot de passe sur votre compte Secure Exchanges : quiconque les détient peut envoyer, lire et supprimer des messages en votre nom, et la consommation vous est facturée. Leur stockage est entièrement votre décision, et votre responsabilité.
- Ne les committez jamais. Gardez-les hors du dépôt, et vérifiez aussi
l'historique :
git log -S <serial>retrouve un secret committé une fois puis retiré. Un secret parti sur un remote est compromis : il faut le régénérer, pas seulement supprimer la ligne. - Ne les écrivez jamais en dur dans le code. Ils se retrouvent dans les traces d'exception, dans les rapports de bogue, dans les paquets que vous distribuez et dans chaque fork du code.
- Privilégiez un gestionnaire de secrets. Chiffrés au repos, accès journalisé, rotation possible sans redéploiement.
- Si vous les gardez dans un fichier, chiffrez-le ou verrouillez-le. Hors
de la racine web, appartenant au compte de service, permissions
0400, et exclu de vos sauvegardes ou chiffré à l'intérieur. - Méfiez-vous de l'environnement du processus. Les variables
d'environnement sont lisibles depuis
/proc/<pid>/environpar tout ce qui tourne sous le même utilisateur, et apparaissent dans les vidages mémoire comme dans la plupart des rapporteurs d'erreurs. Chargez les identifiants au moment où vous en avez besoin plutôt que de les exporter pour toute la durée de vie du processus. - Tenez-les hors de vos journaux. Excluez-les explicitement de votre gestionnaire d'erreurs, de votre rapporteur d'incidents et des vidages de requête, qui capturent l'environnement et les variables locales par défaut.
- Régénérez-les depuis le portail d'administration dès que vous soupçonnez une exposition : un portable perdu, un journal transmis à un tiers, le départ d'un développeur.
Sécurité
- Chiffrement de bout en bout : le contenu (corps du message et fichiers) est chiffré localement, avec des clés générées sur votre machine et jamais transmises au serveur : le serveur ne stocke et ne relaie que des données chiffrées.
- Échange de clés post-quantique : ML-KEM-1024 (FIPS 203), résistant aux attaques par ordinateur quantique, signé en ML-DSA-87 (FIPS 204).
- Chiffrement AES-256 du contenu et des échanges avec le serveur.
- Protection anti-interception : toute tentative d'attaque de type homme du milieu (MITM) fait échouer la connexion.
- Rien à gérer : le SDK applique automatiquement l'intégralité du protocole à chaque appel : vous n'avez aucune primitive cryptographique à manipuler.
Architecture du SDK
Survol des grands modules. Dans la pratique, vous utiliserez surtout les helpers, qui orchestrent le protocole complet pour vous :
| Module | Rôle |
|---|---|
client/ |
Clients HTTP : SecureExchangesClient (API principale), SEMSClient (livraison des courriels) |
helpers/message_helper.py |
Envoi, lecture, suppression de messages, enveloppes de réponse |
helpers/handshake_helper.py |
Handshake post-quantique (ML-KEM-1024 + ML-DSA-87) |
helpers/post_quantum_crypto_helper.py |
Primitives post-quantiques du handshake |
helpers/crypto_helper.py |
Cryptographie symétrique/RSA de bas niveau (AES-256, SHA-512, GUID .NET) |
helpers/logs_helper.py |
Récupération des journaux de messages |
helpers/sign_helper.py, helpers/zone_builder.py |
Zones de signature électronique sur PDF |
helpers/pki_file_helper.py |
Certification PKI de PDF (navigateur headless) |
helpers/file_helper.py |
Upload/download chiffré de fichiers (par morceaux, parallèle) |
helpers/settings_helper.py |
Configuration (environnements, endpoints) |
helpers/contact_helper.py, licence_helper.py |
Contacts, validation de licence |
helpers/email_helper.py, phone_helper.py, mime_helper.py |
Validations (courriel, téléphone, types MIME) |
models/ |
Modèles de données : réponses (answer/), entités (entity/), énumérations (enum/), transport, JSON |
callback/ |
Modèles pour les callbacks de notification |
Guide d'utilisation
Tous les exemples ci-dessous supposent la configuration suivante (voir Configuration) :
from secure_exchanges_sdk.client import SecureExchangesClient, SEMSClient
from secure_exchanges_sdk.helpers.settings_helper import SettingsHelper
cfg = SettingsHelper.configure_production()
client = SecureExchangesClient(cfg['api_endpoint'])
sems_client = SEMSClient(cfg['sems_endpoint'])
# Votre propre fonction : elle retourne les trois UUID de votre licence.
serial, api_user, api_password = charger_mes_identifiants()
Envoi d'un message simple
from secure_exchanges_sdk.helpers.message_helper import MessageHelper
from secure_exchanges_sdk.models.entity.recipient_info import RecipientInfo
recipients = [
RecipientInfo(email="destinataire@example.com")
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Bonjour, voici un message sécurisé.</p>",
subject="Message confidentiel",
culture_id="fr-CA"
)
if answer.status == 200:
print("Message envoyé avec succès!")
for ra in answer.recipients_answer:
if ra.answer and ra.answer.url:
print(f" URL: {ra.answer.url}")
else:
print(f"Erreur {answer.status}: {answer.data}")
Envoi avec mot de passe et code SMS (2FA)
from secure_exchanges_sdk.models.enum.send_method_enum import SendMethodEnum
recipients = [
RecipientInfo(email="user@example.com", phone="+15145551234")
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Document confidentiel ci-joint.</p>",
subject="Document protégé",
password="MotDePasseSecret123",
send_method=SendMethodEnum.EMAIL_WITH_SMS_CODE, # lien par courriel, code par SMS
culture_id="fr-CA",
maximum_open_time=3, # Nombre max d'ouvertures (1-99)
minutes_expiration=1440 # Expiration en minutes (1440 = 24h)
)
Valeurs de SendMethodEnum :
| Valeur | Description |
|---|---|
ONLY_EMAIL (0) |
Lien envoyé par courriel uniquement (défaut) |
SMS_ONLY (1) |
Lien envoyé par SMS uniquement |
SMS_WITH_EMAIL_CODE (2) |
Lien par SMS, code d'ouverture par courriel |
EMAIL_WITH_SMS_CODE (3) |
Lien par courriel, code d'ouverture par SMS |
La protection par mot de passe (
password) est indépendante du canal d'envoi et peut être combinée avec n'importe quelle valeur desend_method.
Envoi avec fichiers joints
# Depuis le disque
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Voir fichiers joints.</p>",
subject="Fichiers sécurisés",
files_path=["/chemin/vers/document.pdf", "/chemin/vers/image.png"]
)
# Depuis la mémoire (bytes)
pdf_bytes = open("/chemin/vers/rapport.pdf", "rb").read()
csv_bytes = open("/chemin/vers/donnees.csv", "rb").read()
files_in_memory = [
{"binary": pdf_bytes, "file_name": "rapport.pdf"},
{"binary": csv_bytes, "file_name": "donnees.csv"}
]
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=recipients,
message="<p>Rapport et données en pièces jointes.</p>",
subject="Rapport mensuel",
files_list=files_in_memory
)
Envoi avec certification PKI
La certification PKI appose un certificat numérique sur un PDF avant l'envoi pour signature. Le processus utilise un navigateur headless (Playwright, extra signature). Les zones de signature se définissent avec ZoneBuilder, qui lit les dimensions réelles des pages du PDF :
import asyncio
from secure_exchanges_sdk.helpers.crypto_helper import CryptoHelper
from secure_exchanges_sdk.helpers.zone_builder import ZoneBuilder
from secure_exchanges_sdk.helpers.sign_helper import SignHelper
from secure_exchanges_sdk.helpers.pki_file_helper import PkiFileHelper, CertifyPdfArgs
from secure_exchanges_sdk.models.entity.sign_zone_definition import SignZoneDefinition
from secure_exchanges_sdk.models.transport.file_zone_definition import FileZoneDefinition
from secure_exchanges_sdk.models.transport.recipient_zone_definition import RecipientZoneDefinition
# 1. Lire le PDF et calculer son SHA512
pdf_path = "contrat.pdf"
with open(pdf_path, "rb") as f:
pdf_bytes = f.read()
sha512 = CryptoHelper.get_sha512_hash_of_bytes(pdf_bytes)
# 2. Définir les zones de signature avec ZoneBuilder
with ZoneBuilder(pdf_path, is_pki=True) as zone_builder:
zones = [
# Zone de signature en page 1
zone_builder.create_field_sign_zone(
page=1, field_name="signature1",
x=60, y=400, width=200, height=50
),
# Zone de date remplie automatiquement à la signature
zone_builder.create_field_date_sign_zone(
page=1, field_name="date1",
x=60, y=500, width=100, height=25, font_size=12
),
]
# 3. Associer les zones au destinataire (fichier référencé par son SHA512)
recipient_zones = [
RecipientZoneDefinition(
email="signataire@example.com",
phone=None,
zones_def_by_file=[
FileZoneDefinition(
unique_name=sha512,
do_not_encrypt_pdf=False,
do_not_append_certificate_to_file=False,
is_pki_file=True,
zones_def=SignZoneDefinition(mode="define", zones=zones)
)
]
)
]
# 4. Obtenir le token de certification
cert_response = SignHelper.get_certification_token(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
original_hash=sha512,
culture_id="fr-CA",
token_type="CertifyDocument"
)
cert_data = cert_response["certification_data"]
# 5. Certifier le PDF via navigateur headless
certify_args = CertifyPdfArgs(
file_bytes=pdf_bytes,
file_name="contrat.pdf",
recipients=["signataire@example.com"],
certify_data=cert_data,
detect_existing_fields=True,
recipient_zone_definitions=recipient_zones
)
async def certify():
async with PkiFileHelper(is_preview=False, culture="fr-CA") as helper:
return await helper.certify_pki_pdf(certify_args)
certified = asyncio.run(certify())
# 6. Envoyer le PDF certifié
answer = MessageHelper.multi_recipient_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
recipients=[RecipientInfo(email="signataire@example.com")],
message="<p>Veuillez signer ce document certifié.</p>",
subject="Document PKI à signer",
certified_pdfs=[certified],
owner_dont_need_to_sign=True,
sems_client=sems_client
)
Un exemple complet et exécutable, incluant les options de signature (SignOptions : restriction du mode de signature, demande de fichier en retour) et les paramètres de callback (clés contextuelles), se trouve dans example_pki_with_signature_options.py à la racine de pythonSDK/.
Récupération d'un message
# Parser un lien Secure Exchanges
link = "https://www.secure-exchanges.com/message.aspx?msgid=xxx&sems=yyy&cpart=zzz"
msg_params = MessageHelper.get_secure_exchanges_message_from_link(link)
# Récupérer et déchiffrer le message
response = MessageHelper.get_message(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
msg_params=msg_params,
password="MotDePasse" # si protégé
)
Note : chaque lecture consomme une ouverture du message (
maximum_open_time).
Journaux de messages
Suivez le cycle de vie de vos messages (envoi, ouvertures, signatures) :
from datetime import datetime, timedelta
from uuid import UUID
from secure_exchanges_sdk.helpers.logs_helper import LogsHelper
# Tous les logs des 60 derniers jours
logs_response = LogsHelper.get_logs(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
from_date=datetime.now() - timedelta(days=60),
to_date=datetime.now()
)
# Le log d'un message précis (par message_id OU tracking_id)
log_response = LogsHelper.get_log(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
tracking_id=UUID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
)
Suppression d'un message
from uuid import UUID
success = MessageHelper.delete_message_by_tracking_id(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
tracking_id=UUID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
)
Enveloppes de réponse
Les enveloppes permettent à un destinataire de vous répondre de manière sécurisée :
# Enveloppe simple (un destinataire)
env_response = MessageHelper.get_enveloppe(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
subject="Envoyez-moi vos documents",
destination="destinataire@example.com",
culture_id="fr-CA",
reply_expiration_hours=48,
maximum_reply_open_time=3,
reply_to_api=True,
authorized_extensions=[".pdf", ".docx"]
)
if env_response.url:
print(f"URL de l'enveloppe: {env_response.url}")
# Enveloppes multiples
env_responses = MessageHelper.get_envelopes(
api_client=client,
serial=serial,
api_user=api_user,
api_password=api_password,
subject="Documents requis",
recipients=[
{"Email": "user1@example.com"},
{"Email": "user2@example.com"}
]
)
Référence API
MessageHelper
Classe statique pour l'envoi et la réception de messages.
| Méthode | Description |
|---|---|
multi_recipient_message(api_client, serial, api_user, api_password, recipients, message, subject, ...) |
Envoie un message à plusieurs destinataires |
get_message(api_client, serial, api_user, api_password, msg_params, password=None, digit_code=None, sems_client=None) |
Récupère et déchiffre un message |
delete_message_by_tracking_id(api_client, serial, api_user, api_password, tracking_id, ...) |
Supprime un message par tracking ID |
get_enveloppe(api_client, serial, api_user, api_password, subject, destination, ...) |
Crée une enveloppe de réponse |
get_envelopes(api_client, serial, api_user, api_password, subject, recipients, ...) |
Crée des enveloppes multiples |
get_secure_exchanges_message_from_link(link) |
Parse un lien SE en paramètres |
send_trace(api_client, trace_content) |
Envoie une trace de support |
Paramètres de multi_recipient_message
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
api_client |
SecureExchangesClient |
requis | Client API |
serial |
UUID |
requis | Numéro de série |
api_user |
UUID |
requis | Identifiant API |
api_password |
UUID |
requis | Mot de passe API |
recipients |
List[RecipientInfo] |
requis | Destinataires |
message |
str |
requis | Contenu HTML du message |
subject |
str |
requis | Sujet du message |
password |
str |
None |
Mot de passe de protection |
files_list |
List[dict] |
None |
Fichiers en mémoire ({"binary": bytes, "file_name": str}) |
files_path |
List[str] |
None |
Chemins de fichiers sur le disque |
send_method |
SendMethodEnum |
ONLY_EMAIL |
Canal d'envoi (voir tableau SendMethodEnum plus haut) |
get_back_html |
bool |
True |
True=vous envoyez l'email, False=SEMS envoie |
show_subject |
bool |
True |
Afficher le sujet dans la notification |
get_notify |
bool |
True |
Notifier à l'ouverture |
culture_id |
str |
"en-US" |
Langue ("fr-CA", "en-US") |
maximum_open_time |
int |
1 |
Nombre max d'ouvertures (1-99) |
minutes_expiration |
int |
10080 |
Expiration en minutes (défaut : 7 jours) |
create_message_copy |
bool |
False |
Copie pour l'expéditeur |
name |
str |
"Secure Exchanges" |
Nom de l'expéditeur |
callback_parameters |
str |
None |
Paramètres libres (JSON) renvoyés dans les callbacks de notification |
reply_options |
dict |
None |
Options de réponse du destinataire (voir ci-dessous) |
owner_dont_need_to_sign |
bool |
True |
L'expéditeur ne signe pas |
certified_pdfs |
List[CertifiedPdfContainer] |
None |
PDFs certifiés PKI |
sign_options |
SignOptions |
None |
Options de signature : restriction de mode, destinataires CC/BCC, options d'upload |
sems_client |
SEMSClient |
None |
Client SEMS (créé automatiquement si omis) |
reply_options est un dictionnaire (clés PascalCase, comme l'API) qui contrôle
ce que le destinataire peut faire en réponse :
from secure_exchanges_sdk.models.enum.reply_file_upload_mode import ReplyFileUploadMode
reply_options = {
"UploadMode": int(ReplyFileUploadMode.UPLOAD_MANDATORY), # NO_UPLOAD, UPLOAD_OPTIONAL, UPLOAD_MANDATORY
"AuthorizedExtensions": [".jpg", ".png", ".pdf"],
"Messages": [
{"CultureID": "fr-CA", "Message": "Veuillez joindre votre document."},
{"CultureID": "en-CA", "Message": "Please attach your document."},
],
"NoEditor": False, # désactiver l'éditeur de texte de réponse
"NoReply": False, # interdire toute réponse
}
sign_options (SignOptions, dans models/json_models/sign_options.py)
permet, pour un envoi en signature : signature_restriction
(SignatureModeRestriction), cc_recipients / bcc_recipients
(destinataires en copie, non-signataires) et upload_file_options.
LogsHelper
Récupération des journaux de messages (envois, ouvertures, activités).
| Méthode | Description |
|---|---|
get_logs(api_client, serial, api_user, api_password, from_date, to_date, user_log_serial=None) |
Tous les logs sur une plage de dates (datetime) → GetLogsResponse |
get_log(api_client, serial, api_user, api_password, message_id=None, tracking_id=None, user_log_serial=None) |
Log d'un message précis : fournir message_id ou tracking_id → GetLogResponse |
SignHelper
Gestion des zones de signature numérique sur les PDF.
| Méthode | Description |
|---|---|
add_file_zone_def_to_recipient_index(recipient_index, template_zones, sha512, recipients_match) |
Convertit des templates en définitions de zones |
convert_recipient_index_to_list(recipient_index) |
Convertit l'index en liste pour multi_recipient_message |
concat_recipient_zone_definition_lists(list1, list2) |
Fusionne deux listes de définitions de zones |
validate_all_recipients_have_zones(files_to_sign, recipients, recipients_zone_def) |
Vérifie que tous les destinataires ont des zones |
validate_document_signature_integrity(api_client, file_sha512) |
Valide l'intégrité d'un document signé |
get_certification_token(api_client, serial, api_user, api_password, original_hash, culture_id, ...) |
Obtient un token de certification PKI |
PkiFileHelper
Certification PKI de PDF via navigateur headless (Playwright, extra signature).
# Asynchrone (recommandé)
async with PkiFileHelper(is_preview=True, culture="fr-CA") as helper:
result = await helper.certify_pki_pdf(args)
# Synchrone
helper = PkiFileHelper(is_preview=True)
result = helper.certify_pki_pdf_sync(args)
helper.close_sync()
CertifyPdfArgs
| Propriété | Type | Description |
|---|---|---|
file_bytes |
bytes |
Contenu binaire du PDF |
file_name |
str |
Nom du fichier |
recipients |
List[str] |
Emails des destinataires |
certify_data |
dict |
Token de certification (de get_certification_token) |
detect_existing_fields |
bool |
Détecter les champs existants (défaut: True) |
recipient_zone_definitions |
List[RecipientZoneDefinition] |
Zones prédéfinies |
define_recipients |
Callable |
Callback pour distribuer les zones entre destinataires |
CertifiedPdfContainer
| Propriété | Type | Description |
|---|---|---|
file_bytes |
bytes |
PDF certifié |
file_name |
str |
Nom du fichier |
sign_file_def |
dict |
Définition de signature (SHA512, IsPKIFile, etc.) |
recipient_zone_definitions |
List[RecipientZoneDefinition] |
Zones mises à jour avec le nouveau SHA512 |
ZoneBuilder
Construction de zones de signature à partir d'un PDF (helpers/zone_builder.py,
extra signature). Le builder lit les dimensions réelles des pages du PDF et
calcule les coordonnées attendues par le serveur.
from secure_exchanges_sdk.helpers.zone_builder import ZoneBuilder
with ZoneBuilder(pdf_path, is_pki=True) as builder:
zone = builder.create_field_sign_zone(
page=1, field_name="signature1",
x=60, y=400, width=200, height=50
)
Types de zones : signature (create_field_sign_zone), date de signature
(create_field_date_sign_zone), initiales, texte, nombre, date, case à cocher,
boutons radio, zone de texte, liste d'options, liste déroulante.
CryptoHelper
Fonctions cryptographiques de bas niveau (normalement utilisées indirectement via les helpers).
| Catégorie | Méthodes |
|---|---|
| AES-256-CBC | encrypt_string_to_bytes, decrypt_string_from_bytes, encrypt_binary, decrypt_binary_from_bytes, encrypt_string_to_b64, decrypt_string_from_base64, encrypt_file, decrypt_file |
| RSA | create_new_private_key, get_public_key_from_private_key, encrypt_rsa_content, decrypt_rsa_content |
| Hachage | get_sha512_hash_of_bytes, get_sha512_hash_of_string, get_sha256_hash_of_bytes, get_sha512_of_file |
| GUID .NET | guid_to_bytes_le, bytes_le_to_guid |
| Clés | generate_aes_keys, generate_secure_random_byte_array |
| Utilitaires | alter_binary, bytes_xor, concat_byte_arrays, hex_to_byte_array |
Modèles de données
RecipientInfo
RecipientInfo(
email="user@example.com",
phone="+15145551234" # Optionnel, active le 2FA par SMS
)
SignZoneDetails
Définit une zone de signature sur un PDF. En pratique, vous n'instanciez pas
SignZoneDetails vous-même : les zones sont créées via
ZoneBuilder, qui calcule les coordonnées pour vous.
SignZoneDetails(
type="sign", # "sign", "initial", "stamp", "text", "checkbox"
page=1, # Numéro de page (1-indexé)
left=100, # Position X (pixels)
top=400, # Position Y (pixels)
width=200, # Largeur (pixels)
height=80, # Hauteur (pixels)
page_height=792, # Hauteur de la page
canvas_width=612, # Largeur du canvas
canvas_height=792, # Hauteur du canvas
rotate_degree=0, # Rotation (0, 90, 180, 270)
default_value=None # JSON string avec métadonnées du champ (requis pour PKI)
)
RecipientZoneDefinition
Associe des zones de signature à un destinataire pour un ou plusieurs fichiers.
RecipientZoneDefinition(
email="signataire@example.com",
phone=None,
zones_def_by_file=[
FileZoneDefinition(
unique_name=sha512, # SHA512 du fichier
do_not_encrypt_pdf=False,
do_not_append_certificate_to_file=False,
is_pki_file=True, # certification PKI
zones_def=SignZoneDefinition(
mode="define",
zones=[...]
)
)
]
)
MultiRecipientAnswer
Réponse de multi_recipient_message :
| Propriété | Type | Description |
|---|---|---|
status |
int |
Code de statut (200=succès) |
data |
str |
Message descriptif |
recipients_answer |
List[RecipientAnswer] |
Réponses par destinataire |
Chaque RecipientAnswer contient un SendMessageAnswer avec url (le lien à envoyer au destinataire).
Support
Pour toute question ou problème, contactez supportdev@secure-exchanges.info ou visitez secure-exchanges.com. Documentation produit : help.secure-exchanges.com.
Licence
Distribué sous licence Apache, version 2.0. Texte complet sur
https://www.apache.org/licenses/LICENSE-2.0. Le copyright figure dans le
fichier NOTICE.
L'utilisation du SDK requiert par ailleurs une licence Secure Exchanges (serial, usager et mot de passe API) obtenue depuis votre portail d'administration. La licence Apache couvre ce code source, pas l'accès au service.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file secure_exchanges_sdk-2026.8.26.tar.gz.
File metadata
- Download URL: secure_exchanges_sdk-2026.8.26.tar.gz
- Upload date:
- Size: 171.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73418879bf01b84d86c6d94f66eb1bbb24e013717ed19e8c1ae0fe89070db1c6
|
|
| MD5 |
8c1a4fdb73fb6e160a69c2badada22fe
|
|
| BLAKE2b-256 |
002fed6187be773ba60b67114ba6ef280957ead190cd3ee0d17a4da6ffce1a0d
|
File details
Details for the file secure_exchanges_sdk-2026.8.26-py3-none-any.whl.
File metadata
- Download URL: secure_exchanges_sdk-2026.8.26-py3-none-any.whl
- Upload date:
- Size: 203.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89ecdd9a1ae68cd7dcec726b606e5513b84ee889255da3cc56b257e9642b2592
|
|
| MD5 |
74c5901471f994b2b0ba76c94a890de3
|
|
| BLAKE2b-256 |
58d6169888e64a077afc0440a24ee9732f4ae501fe55f40b496b69b7c147e329
|