Skip to main content
Documentation

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, limit
  • GET /conversations/:id
  • POST /conversations/:id/messages { body }
  • PATCH /conversations/:id { status }
  • GET /messages?conversationId=…
  • GET /leads, POST /leads, PATCH /leads/:id
  • GET /brands
  • GET /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.created
  • conversation.status_changed
  • message.created (visitor + operator + atlas)
  • lead.created
  • lead.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.