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
Widget user sends their first message — Talki fires a POST to your endpoint
Your endpoint verifies the HMAC-SHA256 signature and returns customer JSON
Talki saves the data and displays it in the ticket sidebar — within seconds
Operators can hit Refresh at any time to re-fetch updated data
Setup
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
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.
window.TalkiConfig = {
orgId: 'YOUR_ORG_ID',
apiKey: 'YOUR_API_KEY',
identity: {
userId: currentUser.id, // sent as userToken in the webhook body
},
};Build your endpoint
Talki sends this request when the first message is received from a user with an identity:
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:
{
"name": "Alice Johnson",
"email": "alice@example.com",
"plan": "pro",
"fields": {
"mrr": 149,
"company": "Acme Inc",
"signedUpAt": "2024-01-15",
"seats": 5
}
}| Name | Type | Description |
|---|---|---|
| name | string | Customer display name. Shown in the ticket panel header. |
| string | Customer email. Shown in the ticket panel and used for email channel threading. | |
| plan | string | Subscription plan name. Rendered as a colored badge (e.g. "pro", "enterprise"). |
| fields | object | Any key-value pairs. Rendered as a list in the customer data sidebar. Accepts strings, numbers, and booleans. |
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
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
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
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.
