Helpdesk · Integration

YourCRM Connector

Connect Disqua Helpdesk to any CRM or database. When a customer emails your support address, Disqua automatically queries your endpoint to identify the sender — showing their name, plan, lifetime value, and a direct link into your CRM — right inside the ticket view.

How it works

Every time a new support ticket is created from an inbound email, Disqua sends a POST request to your configured endpoint with the sender's email address. Your server responds with customer data (or found: false), and Disqua displays it in the ticket detail sidebar — no page refresh needed.

1. Email arrives → support@yourcompany.com
2. Disqua creates ticket from email
3. Disqua POSTs to your endpoint (async, non-blocking):
       POST https://your-api.com/crm/lookup
       X-API-Key: your-secret
       { "email": "jan.novak@company.cz", "ticket_id": "uuid", ... }
4. Your server queries its CRM/database
5. Your server responds with customer data
6. Disqua shows the result in the ticket sidebar:
       ✓ Jan Novák  [Pro zákazník]  Plan: Business  MRR: €149
       [Zobrazit v CRM →]

Async & non-blocking

Lookup runs in the background. Ticket is created immediately — the CRM panel updates when your endpoint responds.

💾

Cached with TTL

Results are cached (configurable TTL). Agents see instant results without re-querying your CRM on every view.

🔗

Deep links

Configure a link template and agents get a one-click button to open the customer record in your CRM.

Setup guide

  1. 1

    Build your lookup endpoint

    Create an HTTP endpoint that accepts POST requests and returns customer data. See Request format and Code examples below.

  2. 2

    Open Helpdesk Settings → YourCRM

    In your Disqua workspace, go to Helpdesk → Settings → YourCRM and click Přidat connector.

  3. 3

    Configure the connector

    Název Human-readable name, e.g. Billing CRM
    Lookup URL Your endpoint URL, e.g. https://api.yourapp.com/crm/lookup
    Secret Header Name HTTP header to send your secret, e.g. X-API-Key
    Secret Header Value Your API key or token (stored AES-256-GCM encrypted)
    Link Template Deep link into CRM, e.g. https://crm.yourapp.com/customers/{customer_id}
    Cache TTL (h) How long to cache lookup results (default: 24 hours)
  4. 4

    Save and verify

    Save the connector. Open an existing email ticket — the YourCRM panel appears in the right sidebar. Use the refresh button to trigger a live lookup and verify the response.

Request format

Disqua sends a POST request to your endpoint with Content-Type: application/json. The request times out after 3 seconds — keep your response fast.

Request headers

POST /crm/lookup HTTP/1.1
Content-Type: application/json
User-Agent: Disqua-CRM-Connector/1.0
X-API-Key: your-secret-here     ← your configured secret header

Request body

{
  "email":        "jan.novak@company.cz",   // sender's email address
  "ticket_id":    "b8a1bf5d-8ce7-46ac-...",  // Disqua ticket UUID
  "workspace_id": "f8e7e88d-2108-11f1-...",  // Disqua workspace UUID
  "source":       "disqua-helpdesk"            // always this value
}

Only the email field is required for your lookup logic. The other fields are provided for logging or routing purposes.

Response format

Your endpoint must respond with HTTP 200 and a JSON body. Any non-2xx response is treated as an error. Response must arrive within 3 seconds.

Customer found

{
  "found":       true,
  "customer_id": "12345",             // used in link_template substitution
  "name":        "Jan Novák",          // displayed in ticket sidebar
  "badge":       "Business zákazník",  // badge label (max 30 chars)
  "badge_color": "green",             // green | blue | yellow | red | gray
  "fields": {                              // max 5 fields displayed
    "Plan":        "Business",
    "MRR":         "€149",
    "Zákazník od": "2023-04-15",
    "Tickets":    "47",
    "NPS":         "9"
  }
}

Customer not found

{
  "found": false
}

When found: false, Disqua shows a "Neznámý" badge with a tooltip linking to this documentation.

All response fields

Field Type Required Description
foundbooleanYesWhether this email is a known customer
customer_idstringNoYour internal customer ID, used in {customer_id} link template
namestringNoCustomer display name shown in the sidebar
badgestringNoShort badge label (max 30 chars), e.g. "Pro Customer", "Free Trial"
badge_colorstringNoOne of: green, blue, yellow, red, gray
fieldsobjectNoKey-value pairs shown in the sidebar (max 5, string values only)

Code examples

Minimal server-side implementations to get you started.

Node.js (Express)

// Install: npm install express
const express = require('express');
const app = express();
app.use(express.json());

app.post('/crm/lookup', async (req, res) => {
  // Verify the secret
  if (req.headers['x-api-key'] !== process.env.DISQUA_SECRET) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  const { email } = req.body;

  // Query your database
  const customer = await db.query(
    'SELECT * FROM customers WHERE email = ?', [email]
  );

  if (!customer) {
    return res.json({ found: false });
  }

  res.json({
    found: true,
    customer_id: customer.id,
    name: customer.full_name,
    badge: customer.plan + ' Customer',
    badge_color: customer.plan === 'business' ? 'green' : 'blue',
    fields: {
      'Plan':       customer.plan,
      'MRR':        '€' + customer.mrr,
      'Member since': customer.created_at.toISOString().slice(0, 10),
      'Tickets':    String(customer.ticket_count),
    },
  });
});

app.listen(3000);

PHP

<?php
// Verify the secret header
if ($_SERVER['HTTP_X_API_KEY'] !== getenv('DISQUA_SECRET')) {
    http_response_code(401);
    die(json_encode(['error' => 'Unauthorized']));
}

$body = json_decode(file_get_contents('php://input'), true);
$email = $body['email'] ?? '';

// Query your database
$stmt = $pdo->prepare('SELECT * FROM customers WHERE email = ?');
$stmt->execute([$email]);
$customer = $stmt->fetch();

header('Content-Type: application/json');

if (!$customer) {
    echo json_encode(['found' => false]);
    exit;
}

echo json_encode([
    'found'       => true,
    'customer_id' => $customer['id'],
    'name'        => $customer['full_name'],
    'badge'       => ucfirst($customer['plan']) . ' Customer',
    'badge_color' => 'green',
    'fields'      => [
        'Plan'    => $customer['plan'],
        'MRR'     => '€' . $customer['mrr'],
        'Tickets' => (string)$customer['ticket_count'],
    ],
]);

Python (Flask)

# pip install flask
from flask import Flask, request, jsonify
import os

app = Flask(__name__)

@app.route('/crm/lookup', methods=['POST'])
def crm_lookup():
    # Verify the secret
    if request.headers.get('X-API-Key') != os.environ['DISQUA_SECRET']:
        return jsonify({'error': 'Unauthorized'}), 401

    email = request.json.get('email')

    # Query your database
    customer = db.session.query(Customer).filter_by(email=email).first()

    if not customer:
        return jsonify({'found': False})

    return jsonify({
        'found':       True,
        'customer_id': str(customer.id),
        'name':        customer.full_name,
        'badge':       customer.plan.title() + ' Customer',
        'badge_color': 'green',
        'fields': {
            'Plan':    customer.plan,
            'MRR':     f'€{customer.mrr}',
            'Tickets': str(customer.ticket_count),
        }
    })

Badge colors

Your endpoint controls the badge color. Use it to communicate customer tier or status at a glance.

green — paying / pro blue — standard / verified yellow — trial / warning red — churned / blocked gray — free / unknown

Caching & TTL

Disqua caches lookup results to avoid re-querying your endpoint on every ticket view. Configure the Cache TTL to balance freshness vs. load on your CRM.

TTL Recommended for
0 hoursAlways re-query — for real-time data (high CRM load)
1 hourFast-changing data (trial status, support credits)
24 hours (default)Plan, MRR, registration date — changes slowly
168 hoursStatic data (customer ID, company) — changes rarely
Manual refresh: Agents can click the refresh icon in the CRM panel to force a fresh lookup regardless of cache TTL. Useful after a customer upgrades their plan.

Security

Verifying requests from Disqua

Configure a Secret Header in Disqua and verify it on your endpoint. The secret is stored AES-256-GCM encrypted in Disqua's database and never logged.

// Node.js — verify secret header
const SECRET = process.env.DISQUA_CRM_SECRET;

app.post('/crm/lookup', (req, res) => {
  const incoming = req.headers['x-api-key'];

  // Use timing-safe comparison to prevent timing attacks
  if (!incoming || !crypto.timingSafeEqual(
    Buffer.from(incoming),
    Buffer.from(SECRET)
  )) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  // proceed...
});

Best practices

  • Use HTTPS only for your lookup endpoint
  • Generate a long random secret (min 32 chars), e.g. openssl rand -hex 32
  • Use timing-safe comparison for the secret (not ===)
  • Return only the minimum necessary data (avoid sending full customer objects)
  • If you're GDPR-strict, disable Log results in connector settings — Disqua will not store the raw response
  • Don't include sensitive fields (passwords, card data, full address) in fields

Error handling

Status Disqua shows When
found Customer panel with data 200 + found: true
not_found "Neznámý" badge + ⓘ tooltip 200 + found: false
error "Chyba" badge + HTTP status Non-2xx response or invalid JSON
timeout "Timeout (3s)" badge No response within 3 seconds
Timeout note: If your endpoint occasionally times out, the agent can use the Refresh button to retry. Disqua does not automatically retry timed-out lookups — the agent controls when to re-query.

Error log

In Helpdesk → Settings → YourCRM, select a connector and click Načíst log to see the last 10 lookup results — including errors, HTTP status codes, and timestamps. Use this to debug why lookups are failing.

Testing your endpoint

Test with curl

curl -s -X POST https://your-api.com/crm/lookup \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret" \
  -d '{
    "email": "test@example.com",
    "ticket_id": "test-ticket-id",
    "workspace_id": "test-workspace-id",
    "source": "disqua-helpdesk"
  }'

Test in Disqua

  1. 1.Save the connector in Helpdesk → Settings → YourCRM
  2. 2.Open any email ticket (or create a test one)
  3. 3.Find the YourCRM panel in the right sidebar
  4. 4.Click the refresh icon to trigger a live lookup
  5. 5.Check the error log in settings if it shows an error status

Multiple connectors

Your workspace can have multiple CRM connectors. Each one queries a different endpoint and shows a separate panel in the ticket sidebar. Useful when customer data lives in multiple systems:

Example: SaaS company

  • Connector 1: Stripe — plan, MRR, payment status
  • Connector 2: Internal DB — feature flags, usage

Example: E-commerce

  • Connector 1: Shopify — orders, LTV, segments
  • Connector 2: Loyalty system — points, tier