# Znatoka — Integration guide (LLM-ready)
> Chat as a service, multi-tenant. Two ways to use it:
> 1. Contact-safe buyer<->seller dispute chat: both parties chat over a secret
> link WITHOUT seeing each other's real phone/username/contact. You drive it
> over a REST API + HMAC webhook.
> 2. Support widget for your own site: one ",
"seller_embed": ""
}
Send buyer_url to the buyer and seller_url to the seller. Or drop the ready
buyer_embed / seller_embed
Options: data-position="left|right", data-color="#5b7cfa", data-label="Help",
data-fullscreen="mobile|always|off" (default "mobile" = opens full-screen on phones).
## Support widget — visitor -> you (different from embed.js)
embed.js needs a token per party (buyer<->seller disputes you create from your
backend). For plain visitor->support chat on your OWN site, use widget.js: one
line on every page, no backend call, no token to manage.
- widget_key ("wk_...") is PUBLIC — safe in page source. Your api_key is NOT.
- Each visitor gets a random id in localStorage; ONE open conversation per
visitor is created/restored via POST /w/:widgetKey/session, so a returning
visitor lands back in the same thread. Read/reply in the admin inbox.
- Options: data-position, data-color, data-label, data-fullscreen (as above),
plus data-title-alert="on|off".
### Unread badge (on by default, no setup)
A red count appears on the bubble when a reply arrives while the panel is closed.
It works because widget.js loads the chat iframe HIDDEN as soon as the page does,
so its SSE stream is connected before the bubble is ever clicked; the iframe
posts {type:"cdj:unread", count} to the parent, which draws the badge. The count
resets when the visitor opens the panel, and last-read is kept per browser in
localStorage (cdj_read_), so a reload does not re-announce read messages.
If the tab is in the BACKGROUND, the page title also blinks "(N) Pesan baru" and
is restored on return; disable with data-title-alert="off".
NOTE: the badge and the title blink are the only signals raisable on the host
page. Sound + desktop notifications exist inside the chat UI, but browsers block
both from a cross-origin frame — do not rely on them for a closed panel.
## Errors
Non-2xx returns { "error": "" }, e.g. invalid_api_key (401),
quota_exceeded (402). During beta the Free plan has a monthly conversation quota;
Pro is unlimited.
## Integration checklist
[ ] Store api_key + webhook_secret server-side (never ship to the browser).
[ ] On a dispute/refund, POST /api/v1/conversations, keep the returned id.
[ ] Deliver buyer_url/seller_url (or buyer_embed/seller_embed) to each party.
[ ] (Optional) Expose a webhook endpoint; verify X-Chatdisiniaja-Signature over the raw body.
[ ] (Optional) On webhook, notify notify_role via open_conversation_url — skip if you
rely on the embed widget / SSE, or poll the transcript.
[ ] Close the conversation when the dispute is resolved.