Build with PraxTalk.
Three integration paths: drop in the widget, hit the REST API from your CRM, or subscribe to webhooks for event-driven workflows. Pick one or combine.
Install the widget
A single <script> tag drops the chat widget on any page. No npm install, no bundler change.
Find your brand widget id at /app/brands in the dashboard. Then paste the snippet into the page, just before </body>:
<script src="https://www.praxtalk.com/widget.js" data-widget-id="ws_…" defer ></script>
The widget loads in a Shadow DOM so host-page styles can't leak in. First-time visitors fill a Name / Email / Phone / Message form before chat starts; subsequent visits skip it.
REST API
Authenticated with Bearer tokens. Mint keys at /app/integrations.
→ Full REST reference (auth, all endpoints, rate limits, webhooks, signature verification).
Base URL: https://industrious-moose-892.convex.site/api/v1
# List inbox
curl -H "Authorization: Bearer ptk_live_…" \
"$BASE/api/v1/conversations?status=open&limit=50"
# Operator reply
curl -X POST -H "Authorization: Bearer ptk_live_…" \
-H "Content-Type: application/json" \
-d '{"body":"Thanks — looking into it now."}' \
"$BASE/api/v1/conversations/<id>/messages"
# Create lead
curl -X POST -H "Authorization: Bearer ptk_live_…" \
-H "Content-Type: application/json" \
-d '{"name":"Maya A.","email":"maya@acme.com"}' \
"$BASE/api/v1/leads"Endpoints
GET /conversations— query:status,brandId,limitGET /conversations/:idPOST /conversations/:id/messages—{ body }PATCH /conversations/:id—{ status }GET /messages?conversationId=…GET /leads,POST /leads,PATCH /leads/:idGET /brandsGET /ping(health)
Brand-scoped keys can only see/act on their own brand; cross-brand calls return 403.
Webhooks
Push events to your CRM the moment they happen. Each request signed with HMAC-SHA256.
Configure endpoints at /app/integrations. Events available:
conversation.createdconversation.status_changedmessage.created(visitor + operator + atlas)lead.createdlead.status_changed
Signature verification
// Each request includes:
// X-PraxTalk-Signature: t=<unix>,v1=<hmacHex>
// X-PraxTalk-Event: conversation.created | message.created | …
// Compute HMAC-SHA256 over: `${ts}.${rawBody}` with your shared secret
import crypto from "crypto";
function verify(secret, signatureHeader, rawBody) {
const m = signatureHeader.match(/t=(\d+),v1=([a-f0-9]+)/);
if (!m) return false;
const expected = crypto.createHmac("sha256", secret)
.update(`${m[1]}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(m[2]), Buffer.from(expected));
}Failed deliveries retry on a backoff schedule of 30s → 2m → 10m → 1h → 6h; after 6 attempts the event is marked failed and surfaces in the dashboard event log with a manual Retry now button.
Agent SDK
For real-time inboxes inside your CRM. Subscribes via Convex websocket so updates push, not poll.
import { ConvexClient } from "convex/browser";
const client = new ConvexClient(process.env.PRAXTALK_CONVEX_URL!);
client.onUpdate(
"conversations:listInbox",
{ sessionToken: "<operator token>", status: "open" },
(rows) => renderInbox(rows),
);The Convex client is the same one PraxTalk's own dashboard uses. For server-to-server (no operator session), use the REST API or webhooks.