For Developers
Contacts
A contact is a customer who reaches support. The API finds a contact by telegram_id or email. Put your own data (a CRM ID, a plan, and so on) in extra_data, a free-form JSON object that operators see on the contact card.
Contact object
{
"id": "44e1...",
"workspace_id": "1c2b...",
"channel_id": null,
"external_id": null,
"internal_id": null,
"telegram_id": 123456789,
"email": "john@example.com",
"full_name": "John Smith",
"username": "johns",
"extra_data": { "plan": "pro", "crm_id": "user-42" },
"created_at": "2026-04-01T08:00:00",
"updated_at": "2026-04-06T10:12:33"
}Other contact identifiers (VK, WhatsApp) aren’t returned by the API; a phone number from the widget is in extra_data.phone.
GET
/api/v1/contactsList contacts
Newest first.
Query parameters:
search: a substring of the name, username, external or internal ID, Telegram ID or VK ID. An email matches only in full: addresses are stored encrypted, so there is no search by part of an addresspage(default 1),page_size(default 50, max 100)
Response: {"items": [...], "total": 42, "page": 1, "page_size": 50}
GET
/api/v1/contacts/{contact_id}A contact by ID
Returns the contact object. Unknown id: 404 CONTACT_NOT_FOUND.
POST
/api/v1/contactsFind or create a contact
Needs at least one of telegram_id and email, otherwise 400. The contact is looked up by telegram_id, then by email:
- Found: only
full_nameis updated (andusernamewhen the contact was found bytelegram_id). An existing contact’s email, Telegram ID andextra_datadon’t change. - Not found: created with all the fields you sent.
Either way the response is 201 with the contact object.
body
{
"email": "john@example.com",
"telegram_id": 123456789,
"full_name": "John Smith",
"username": "johns",
"extra_data": { "plan": "pro", "country": "GB", "crm_id": "user-42" }
}Contacts can’t be changed or deleted through the API. Contacts created through the API don’t trigger the contact.created webhook: it fires only when the widget identifies a visitor for the first time.
Was this page helpful?

