For developers

WidgetChat API and webhooks

The conversations with your website visitors are available to outside code: your CRM, a scenario in an integration builder or a script on your server. Read messages, reply and receive events with a key issued in the dashboard.

What you can do

  • Read conversations — The list of the site's conversations filtered by state and time, one conversation's card and the whole exchange page by page.
  • Reply to a visitor — The reply shows up in the chat window on the site exactly like a reply from Telegram and joins the shared history.
  • Close a conversation — The conversation is marked closed; the visitor's next message starts the following one.
  • Fetch an attachment — Visitor files are downloaded with the key, and events carry a temporary signed link — the other server opens it without holding our key.
  • Receive events — A new conversation, a new message, a closed conversation and visitor details are pushed to your address.

The access key

The key is issued in the dashboard for one site: the API and webhooks section in the connection card. The value is shown once — we keep only its fingerprint, a key cannot be recovered, and a lost one is revoked and issued again.

The full description of methods, fields and error codes lives in the documentation.

The key is a server key. It must not go into your page code: any visitor would read it there and get access to every conversation.

curl https://api.widgetchat.ru/api/v1/conversations \
  -H "Authorization: Bearer wck_your_key"

Replying to a visitor

Sending again with the same Idempotency-Key header does not create a second reply: the connection can drop after the request was already accepted, and a retry without that key would double the message in the conversation.

curl -X POST https://api.widgetchat.ru/api/v1/conversations/<id>/messages \
  -H "Authorization: Bearer wck_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reply-4417" \
  -d '{"content": "Your order is on the way, delivery tomorrow before 2 pm"}'

Events on your address

The address and the set of events are configured in the dashboard next to the keys. Event names: conversation.started, message.created, conversation.closed, visitor.identified. The message.created event arrives for messages in both directions, so a message carries an origin field — it shows that the reply was written by your own program and does not have to be sent again.

A 2xx answer means accepted. A 4xx is not retried: the recipient will not change its mind. Everything else — a dropped connection, a 500, a timeout — is retried three times with a growing pause, after which the attempts are visible in the delivery log in the dashboard.

POST /your-handler HTTP/1.1
Content-Type: application/json
X-WidgetChat-Event: message.created
X-WidgetChat-Delivery: message.created:8f1c…
X-WidgetChat-Attempt: 1
X-WidgetChat-Timestamp: 1755878400
X-WidgetChat-Signature: sha256=6b2f…

{"id":"message.created:8f1c…","event":"message.created","createdAt":"2026-08-22T12:00:00Z",
 "workspaceKey":"example-ru","data":{"conversation":{…},"message":{…}}}

Checking the signature

What is signed is not the body alone but the timestamp and the body joined by a dot. A signature over a bare body could be replayed a day later and the handler would not tell the replay from a fresh event; the timestamp inside the signature makes such a replay visible.

Check three things: the signature matches, the timestamp is no more than five minutes away from your clock, and the delivery id from the X-WidgetChat-Delivery header has not been seen before. A retry arrives with the same id — an event already taken into work is dropped by it.

# Go
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(timestampHeader + "." + string(body)))
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))

The signing secret is shown once when the address is created. Forgot it — replace it with the button in the dashboard and write the new one into your handler.

Limits and rules

  • HTTPS only — Both for API requests and for the address events are sent to.
  • 300 requests per minute per key — Above the limit the answer is 429 with a Retry-After header.
  • One response envelope — A successful answer carries a data field, a failure carries an error field with a code and an explanation.
  • Sites are isolated — A key opens the conversations of the site it was issued for. A neighbouring connection's conversation is not found with it.

Frequently asked questions

Where do I get the access key?

In the dashboard, in the connected site's card — the API and webhooks button. The key is shown once when created: we keep only its fingerprint.

How is a webhook different from polling the API?

A webhook arrives by itself at the moment of the event; polling means asking us on a schedule. For a CRM and notifications take webhooks, for exporting history take ordinary API requests.

What if my server did not answer?

The event is retried three times with a growing pause. If that did not help, the attempts stay in the delivery log in the dashboard with the response code and the error text.

Can I connect WidgetChat to my CRM?

Yes, through this API: conversations are read with requests, replies are sent with a request, and events arrive on your address. The full list of methods, fields and error codes is in the documentation at /docs/.

Is the Telegram chat visible through the API?

The API works with the messages that came from the widget on the site. Operator replies from Telegram are visible in that conversation — they are part of the same history.

Read next

Add the chat to your website

Sign up with email or Telegram, set it up in the dashboard, paste one line of code. Free right now.