Talki

Platform

Backend Connect

When a widget user sends their first message, Talki calls your backend to fetch their profile — name, email, plan, and any custom fields. Operators see it live in the ticket panel. No polling, no manual lookups.

How it works

1

Widget user sends their first message — Talki fires a POST to your endpoint

2

Your endpoint verifies the HMAC-SHA256 signature and returns customer JSON

3

Talki saves the data and displays it in the ticket sidebar — within seconds

4

Operators can hit Refresh at any time to re-fetch updated data

Setup

1

Enable Backend Connect

In your Console, go to Admin → Backend Connect. Enter your endpoint URL and save — you'll receive a signing secret. Copy it: it's only shown once.

Endpoint URL — the HTTPS URL Talki will POST to

User token field — key name for the visitor ID (default: userToken)

Signing secret — store this in your env vars for HMAC verification

2

Pass the user ID from the widget

Set identity.userId in your widget config to your logged-in user's ID. Talki sends this value as userToken in the POST body.

javascript
window.TalkiConfig = {
  orgId:  'YOUR_ORG_ID',
  apiKey: 'YOUR_API_KEY',
  identity: {
    userId: currentUser.id,   // sent as userToken in the webhook body
  },
};
3

Build your endpoint

Talki sends this request when the first message is received from a user with an identity:

http
POST /your-endpoint HTTP/1.1
Content-Type: application/json
X-Talki-Signature: a3f8c2...  (HMAC-SHA256 hex of the raw body)

{ "userToken": "usr_abc123" }

Your endpoint must respond within 5 seconds with a JSON object. All fields are optional — return whatever is useful:

json
{
  "name":  "Alice Johnson",
  "email": "alice@example.com",
  "plan":  "pro",
  "fields": {
    "mrr":       149,
    "company":   "Acme Inc",
    "signedUpAt": "2024-01-15",
    "seats":     5
  }
}
NameTypeDescription
namestringCustomer display name. Shown in the ticket panel header.
emailstringCustomer email. Shown in the ticket panel and used for email channel threading.
planstringSubscription plan name. Rendered as a colored badge (e.g. "pro", "enterprise").
fieldsobjectAny key-value pairs. Rendered as a list in the customer data sidebar. Accepts strings, numbers, and booleans.
4

Verify the signature

Always verify X-Talki-Signature before trusting the payload. Compute the HMAC over the raw request body — not the parsed JSON.

Node.js / Express

javascript
const crypto = require('crypto');

// Install: npm install express
app.post('/talki/customer', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-talki-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.TALKI_SECRET)
    .update(req.body)            // raw Buffer — do NOT parse before verifying
    .digest('hex');

  if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { userToken } = JSON.parse(req.body);
  const user = await db.users.findById(userToken);
  if (!user) return res.status(404).json({ error: 'User not found' });

  res.json({
    name:   user.name,
    email:  user.email,
    plan:   user.plan,           // rendered as a badge in Talki
    fields: {
      mrr:       user.mrr,
      company:   user.company,
      signedUpAt: user.createdAt,
    },
  });
});

Python / Flask

python
import hmac, hashlib, json, os
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/talki/customer', methods=['POST'])
def talki_customer():
    sig = request.headers.get('X-Talki-Signature', '')
    raw = request.get_data()    # raw bytes before any parsing
    expected = hmac.new(
        os.environ['TALKI_SECRET'].encode(),
        raw,
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(sig, expected):
        return jsonify(error='Invalid signature'), 401

    body = json.loads(raw)
    user = db.get_user(body['userToken'])

    return jsonify(
        name=user.name,
        email=user.email,
        plan=user.plan,
        fields={'mrr': user.mrr, 'company': user.company},
    )

Use constant-time comparison

Always use crypto.timingSafeEqual (Node.js) or hmac.compare_digest (Python) when comparing signatures. Regular string equality is vulnerable to timing attacks.

Rotating the secret

In Admin → Backend Connect → Signing secret, click Rotate. Talki generates a new secret immediately. Copy it, update your environment variable, and redeploy. Requests signed with the old secret will start failing once rotated — do this during low-traffic periods.

Common questions

What if my endpoint is down?

Talki retries once after 3 seconds, then silently skips. The ticket still opens — operators can click Refresh in the customer panel when you're back up.

Can I return different fields for different users?

Yes. The fields object is fully flexible — return as many or as few keys as you want per user.

Is the signing secret the same as my API key?

No. The signing secret is only for Backend Connect HMAC verification. It is separate from your public widget API key.

When does Talki call my endpoint?

Only once per ticket — when the first message is sent by a user with an identity. Operators can also trigger a manual refresh.