Kommo + Qwilr: Interactive Proposals from the Deal Card with View Tracking

Qwilr is a platform for creating sales proposals in the format of interactive web pages. Instead of PDF — a live page with video, ROI calculators, built-in electronic signature, and analytics: who opened it, how long they spent, and which sections they read. Unlike PandaDoc or GetAccept, Qwilr builds a web experience rather than an electronic document. Without Kommo integration, a manager creates proposals manually. With the integration, Won -> proposal with deal data is sent to the client in 30 seconds.

Qwilr vs PandaDoc vs GetAccept: Proposal Formats

ParameterQwilrPandaDocGetAccept
FormatWeb page (URL)PDF + rich contentPDF + video
View analyticsDetailed (section-level)BasicAvailable
ROI calculatorsBuilt-in, interactiveNoNo
E-signYesYesYes
BrandingFullFullPartial
Best forB2B SaaS, agenciesAnySales + video pitches

Qwilr wins when the product or service requires explanation: interactive pricing calculator, video demo inside the proposal, content adaptable to client segment.

What Gets Synchronised

Kommo -> Qwilr: — Won -> create Document from template with data (name, company, amount, plan) — Save proposal URL in Note and deal field

Qwilr -> Kommo:proposal.viewed -> Note: “Qwilr: client opened the proposal (X min)” — proposal.accepted (signed) -> Note + stage change to “Proposal Accepted” — proposal.declined -> Note + task: “Client declined — clarify objections” — proposal.expired -> Note + task: “Proposal expired — resend”

Qwilr API: Key Requests

Base URL: https://api.qwilr.com/v1. Authentication: Authorization: Bearer {api_key}. API Key: Qwilr -> Settings -> Integrations -> API.

import requests

QWILR_API_KEY = "your_api_key"
QWILR_BASE_URL = "https://api.qwilr.com/v1"
HEADERS = {
    "Authorization": f"Bearer {QWILR_API_KEY}",
    "Content-Type": "application/json",
}

def list_templates() -> list:
    # Get list of templates to select the right one
    resp = requests.get(f"{QWILR_BASE_URL}/templates", headers=HEADERS)
    resp.raise_for_status()
    return resp.json().get("data", [])

def create_document(template_id: str, name: str, tokens: dict) -> dict:
    # tokens - template variables: {ClientName}, {CompanyName}, {Price}, etc.
    payload = {
        "template_id": template_id,
        "name": name,
        "tokens": tokens,
    }
    resp = requests.post(
        f"{QWILR_BASE_URL}/documents",
        headers=HEADERS,
        json=payload,
    )
    resp.raise_for_status()
    return resp.json()

def get_document(document_id: str) -> dict:
    resp = requests.get(
        f"{QWILR_BASE_URL}/documents/{document_id}",
        headers=HEADERS,
    )
    resp.raise_for_status()
    return resp.json()

def on_deal_won(lead: dict, contact: dict):
    name = contact["name"]
    email = get_contact_email(contact)
    company = get_custom_field(lead, COMPANY_FIELD_ID) or name
    plan = get_custom_field(lead, PLAN_FIELD_ID) or "Growth"
    amount = lead.get("price", 0)

    tokens = {
        "ClientName":   name,
        "CompanyName":  company,
        "ClientEmail":  email,
        "PlanName":     plan,
        "Price":        f"${amount:,.0f}",
        "DealId":       str(lead["id"]),
    }

    doc = create_document(
        template_id=QWILR_TEMPLATE_ID,
        name=f"Proposal for {company}",
        tokens=tokens,
    )

    doc_id   = doc["id"]
    view_url = doc.get("view_url", "")

    update_kommo_deal(lead["id"], {"qwilr_document_id": doc_id})
    create_kommo_note(lead["id"],
        f"Qwilr: proposal created\nClient link: {view_url}")

Handling Qwilr Webhook:

@app.route("/webhooks/qwilr", methods=["POST"])
def qwilr_webhook():
    payload = request.json
    event   = payload.get("event")
    doc_id  = str(payload.get("document", {}).get("id", ""))

    deal_id = find_deal_by_field("qwilr_document_id", doc_id)
    if not deal_id:
        return "", 200

    if event == "proposal.viewed":
        duration = payload.get("metadata", {}).get("duration_seconds", 0)
        mins = duration // 60
        create_kommo_note(deal_id,
            f"Qwilr: client opened the proposal ({mins} min)")

    elif event == "proposal.accepted":
        signer = payload.get("signer", {}).get("name", "")
        update_kommo_deal(deal_id, {"stage_id": STAGE_PROPOSAL_ACCEPTED})
        create_kommo_note(deal_id,
            f"Qwilr: proposal accepted and signed ({signer})")

    elif event == "proposal.declined":
        reason = payload.get("metadata", {}).get("reason", "")
        create_kommo_note(deal_id,
            f"Qwilr: client declined the proposal. Reason: {reason}")
        create_kommo_task(deal_id,
            "Clarify objections - client declined the Qwilr proposal")

    return "", 200

View Tracking: Why It Matters for Sales

Qwilr shows: who opened it, when, and how long they spent on each section. Through the Kommo integration, this appears in the deal card. Practical scenarios:

  • Client opened the proposal and spent 12 minutes on the Pricing section -> Note in Kommo -> manager sees this and calls with a specific price offer
  • Client opened it, stayed 30 seconds -> Note -> manager understands the proposal was not read and reformats it

Without the integration, this data stays in Qwilr and managers never see it.

Real-World Case

Digital agency (UK, 30–40 proposals per month, Kommo + Qwilr):

  • Before: PandaDoc, PDF, 20–30 minutes to create a proposal manually. No view analytics. The manager did not know whether the client had looked at it.
  • After: Won -> Qwilr from template in 60 seconds. proposal.viewed -> Note -> manager calls 30 minutes after viewing. Proposal conversion: 34% (was 21%). Time to close shortened from 18 to 11 days.
  • Additionally: ROI calculator in the proposal — the client enters their own data and sees their own outcome. The manager can see in tracking how long they spent on the calculator.

Who This Is Relevant For

  • Agencies and consultancies with 10+ proposals per month
  • SaaS with enterprise sales: proposals requiring ROI justification
  • Companies where PDF proposals regularly “get lost” in the client’s inbox
  • Teams where the manager does not know “did the client look at our proposal”

Frequently Asked Questions

Qwilr vs PandaDoc — when to choose which?

PandaDoc: PDF format is required (legal documents, enterprise with paper trail requirements), forms for data collection inside the document are needed. Qwilr: maximum visual impact, interactive calculators, video inside, detailed tracking. For agencies with modern clients — Qwilr looks significantly more professional.

Qwilr tokens — how do I find out which variables the template supports?

Via GET /templates/{id} — the response contains a tokens array with variable names. Or in the Qwilr editor: { -> list of available variables. Variables can be added directly in the editor before the name using double curly braces.

Does Qwilr support legally binding electronic signatures?

Yes, Qwilr e-sign is a Simple Electronic Signature, legally valid in most jurisdictions (equivalent to DocuSign SES). For a Qualified Electronic Signature (QES, mandatory in some EU contracts) — a separate tool such as Docuseal or Oneflow with a QES provider is needed.

Not natively, but through the integration: after document creation, view_url is saved in a Note and custom field. The manager copies the link from the field and sends it via WhatsApp or email directly from Kommo. Automated sending via Kommo SendGrid or email integration — the next automation step.

Summary

  • Qwilr API: Authorization: Bearer {api_key}, https://api.qwilr.com/v1
  • Create document: POST /documents with template_id and tokens
  • Webhook: proposal.viewed, proposal.accepted, proposal.declined
  • View tracking -> Note in Kommo -> manager knows when to call
  • Web page format instead of PDF — higher engagement, detailed analytics

If you use Qwilr and Kommo and want to automate proposal creation on Won — describe your template structure and variables. Exceltic.dev will configure the integration with view tracking.

More articles

All →