Kommo + Yousign: electronic document signing for EU teams from the sales pipeline

Yousign is an EU-native electronic signature platform: eIDAS-compliant (EU Regulation on trusted electronic services), Qualified Electronic Signatures (QES) for documents requiring the highest legal standing, servers in Europe, GDPR-compliant. Unlike DocuSign or Adobe Sign, Yousign was built for the EU market — qualified e-signatures under French and German law, notarial documents, banking agreements. There is no native integration with Kommo — below we cover the correct architecture using the Yousign API v3.

Yousign vs DocuSign vs Adobe Sign for EU teams

ParameterYousignDocuSignAdobe Sign
JurisdictionEU-native (eIDAS)US (eIDAS via partner)US (eIDAS via partner)
Qualified e-signatureYes (QES)Via TSP partnerVia TSP partner
ServersEU (France, GDPR)US + EU PoPUS + EU PoP
Pricefrom €25/monthfrom $15/user/monthfrom $15/user/month
APIREST v3 (modern)REST (complex)REST
Best forEU teams with legal requirementsGlobal companiesGlobal companies

Yousign is chosen by EU companies where electronic signatures must comply with national legislation (France, Germany, Netherlands) and where data must not leave the EU.

What gets synchronised

Kommo -> Yousign:
— Won (or a custom “Signing” stage) -> create a Signature Request from a template with the contact’s data
— Contact name or email change -> update the signer’s data

Yousign -> Kommo:
request.activated -> Note: “Document sent for signing”
request.completed -> Note: “Document signed by all parties” + move to Won stage
request.expired -> Note + Task: “Signature request expired — resend”
request.declined -> Note: “Signer declined the document”

Yousign API v3: creating a Signature Request

Base URL: https://api.yousign.app/v3. Authentication: Authorization: Bearer {api_key} (from Yousign -> Settings -> API -> Create API Key).

import requests

YS_API_KEY = "your_yousign_api_key"
YS_BASE    = "https://api.yousign.app/v3"
YS_HEADERS = {
    "Authorization": f"Bearer {YS_API_KEY}",
    "Content-Type":  "application/json",
}

def upload_document(file_path: str, file_name: str) -> str:
    # Upload a PDF document and receive a document_id
    with open(file_path, "rb") as f:
        resp = requests.post(
            f"{YS_BASE}/documents",
            headers={"Authorization": f"Bearer {YS_API_KEY}"},
            files={"file": (file_name, f, "application/pdf")},
            data={"nature": "signable_document"},
        )
    resp.raise_for_status()
    return resp.json().get("id")

def create_signature_request(document_id: str, signer_name: str,
                              signer_email: str, signer_phone: str = "") -> dict:
    payload = {
        "name":       f"Contract - {signer_name}",
        "delivery_mode": "email",
        "signers": [
            {
                "info": {
                    "first_name": signer_name.split()[0] if signer_name else "",
                    "last_name":  " ".join(signer_name.split()[1:]) if len(signer_name.split()) > 1 else "",
                    "email":      signer_email,
                    "phone_number": signer_phone or None,
                    "locale":     "fr",
                },
                "signature_level":        "electronic_signature",
                "signature_authentication_mode": "no_otp",
            }
        ],
        "documents": [{"document_id": document_id}],
        "timezone":  "Europe/Paris",
        "expiration_date": None,
    }
    resp = requests.post(
        f"{YS_BASE}/signature_requests",
        headers=YS_HEADERS,
        json=payload,
    )
    resp.raise_for_status()
    return resp.json()

def activate_signature_request(request_id: str) -> dict:
    # Send the signature request to the signers
    resp = requests.post(
        f"{YS_BASE}/signature_requests/{request_id}/activate",
        headers=YS_HEADERS,
    )
    resp.raise_for_status()
    return resp.json()

def on_kommo_deal_won(lead: dict, contact: dict):
    signer_name  = contact.get("name", "")
    signer_email = get_contact_email(contact)
    signer_phone = get_contact_phone(contact)

    # PDF contract template pre-filled with deal/contact data
    pdf_path = generate_contract_pdf(lead, contact)

    doc_id    = upload_document(pdf_path, f"contract_{lead['id']}.pdf")
    sig_req   = create_signature_request(doc_id, signer_name, signer_email, signer_phone)
    req_id    = sig_req.get("id")

    activated = activate_signature_request(req_id)

    save_to_kommo_deal(lead["id"], {"yousign_request_id": req_id})
    create_kommo_note(
        lead["id"],
        f"Yousign: signature request sent - {signer_email} (request ID: {req_id})",
    )

Webhook: Yousign -> Kommo

Yousign Subscriptions (webhooks) are configured via the API: POST /event_subscriptions.

def create_yousign_webhook(callback_url: str) -> dict:
    payload = {
        "url": callback_url,
        "subscribed_events": [
            "signature_request.activated",
            "signature_request.completed",
            "signature_request.expired",
            "signer.declined",
        ],
    }
    resp = requests.post(
        f"{YS_BASE}/event_subscriptions",
        headers=YS_HEADERS,
        json=payload,
    )
    resp.raise_for_status()
    return resp.json()

@app.route("/webhooks/yousign", methods=["POST"])
def yousign_webhook():
    payload    = request.json
    event_name = payload.get("event_name", "")
    request_id = payload.get("data", {}).get("signature_request", {}).get("id", "")

    lead_id = find_kommo_deal_by_custom_field("yousign_request_id", request_id)
    if not lead_id:
        return "", 200

    if event_name == "signature_request.activated":
        create_kommo_note(lead_id, "Yousign: document sent for signing")

    elif event_name == "signature_request.completed":
        create_kommo_note(lead_id, "Yousign: document signed by all parties")
        move_kommo_deal_to_stage(lead_id, SIGNED_STAGE_ID)
        download_and_attach_signed_doc(lead_id, request_id)

    elif event_name == "signature_request.expired":
        create_kommo_note(lead_id, "Yousign: signature deadline expired")
        create_kommo_task(lead_id, "Yousign: resend document for signing")

    elif event_name == "signer.declined":
        signer_email = payload.get("data", {}).get("signer", {}).get("info", {}).get("email", "")
        create_kommo_note(lead_id,
            f"Yousign: signer {signer_email} declined the document")

    return "", 200

def download_and_attach_signed_doc(lead_id: int, request_id: str):
    # Download the signed PDF and save the URL in Kommo
    resp = requests.get(
        f"{YS_BASE}/signature_requests/{request_id}/documents/download",
        headers=YS_HEADERS,
    )
    if resp.ok:
        # Save to S3 / Google Cloud Storage, get URL
        doc_url = save_signed_pdf_to_storage(resp.content, f"signed_{request_id}.pdf")
        create_kommo_note(lead_id, f"Yousign: signed document -> {doc_url}")

Qualified signature (QES): when it is needed

Yousign supports three signature levels in accordance with eIDAS:
SES (Simple Electronic Signature) — email link, sufficient for most B2B contracts
AES (Advanced Electronic Signature) — OTP via SMS + identity verification
QES (Qualified Electronic Signature) — highest legal standing, video identification or eID required

For the Kommo integration, use the signature_level field: "electronic_signature" (SES), "advanced_electronic_signature" (AES), "qualified_electronic_signature" (QES). The choice depends on the jurisdiction and document type.

Real-world case

Law firm (France, 30 people, Kommo + Yousign):

  • Before: Won -> the secretary manually opened Yousign, uploaded the PDF, entered the client’s email, and sent it. 10–15 minutes per document. Signing status was only visible in Yousign — nothing appeared in Kommo.
  • After: Won -> automatic Signature Request created -> request.completed -> Note + stage change. In parallel: the signed PDF is saved to cloud storage and the link is added to the Kommo note.
  • Additional: notarial agreements required AES (OTP via SMS) — the parameter signature_authentication_mode: "otp_sms" was added for that document type.

Who this is relevant for

  • EU companies where DocuSign does not meet jurisdiction or data storage requirements
  • Legal, financial, and notarial firms requiring QES or AES
  • Companies with clients in France, Germany, or the Netherlands — Yousign natively supports local legislation
  • EU startups where data must not leave the EU (GDPR + data residency)

Frequently asked questions

Does Yousign support templates for auto-filling?

Yes. Yousign -> Templates lets you create a document with placeholders ({{first_name}}, {{company}}). When creating a Signature Request via API, you can use a template_id instead of uploading a PDF: POST /signature_requests with "template_id": "tmpl_xxx" and "variables": {"first_name": "...", "company": "..."}. Templates are created once in the Yousign UI and then populated via API.

How to verify the authenticity of a Yousign webhook?

Yousign signs webhooks via HMAC-SHA256: the header is X-Yousign-Signature-256. The verification key (webhook_secret) is set when creating the Event Subscription. Verification: hmac.new(secret.encode(), request.data, sha256).hexdigest() must match the header value.

Yousign API v2 vs v3 — is there outdated code out there?

Yousign v2 (api.yousign.com/v2) — legacy, deprecated in 2024. Yousign v3 (api.yousign.app/v3) — the current version, a different domain and different object structure. If you see examples using /v2 — they are outdated. All new integrations must use v3.

How to add a second signer from your company (bilateral signing)?

Add a second signer — your company’s employee with their email — to the signers array. Yousign sends the request to both parties. Signing order is controlled by the signing_order field: "sequential" (the client signs first, then your employee) or "parallel" (both sign simultaneously).

Summary

  • API: Bearer token, base URL https://api.yousign.app/v3 (v3, not v2)
  • Flow: upload PDF -> create Signature Request -> activate -> webhook -> Note in Kommo
  • Signature levels: SES (default), AES (OTP SMS), QES (maximum legal weight)
  • Webhook verification: X-Yousign-Signature-256 HMAC-SHA256
  • request.completed -> download signed PDF -> save URL in Kommo Note

If you have an EU team with eIDAS-compliant signing requirements and want to automate signing from Kommo — describe your document types and required signature level. Exceltic.dev will set up the integration within 2–3 business days.

More articles

All →