docs Մուտք

API փաստաթղթեր

Ձեր սեփական չատ ինտերֆեյսը՝ վեբ, iOS, Android կամ սերվերային, HighChat բոտի վրա։ Հանրային /v1 API՝ հոսքային պատասխաններ, զրույցի հիշողություն, օպերատորի փոխանցում, CSAT։

Base URL  https://app.highchat.am

Սեփական ինտերֆեյս պետք չէ՞։ Կայքի համար կա պատրաստի վիջեթ՝ մեկ տող («Ալիքներ» → «Կայքի վիջեթ»).

<script src="https://app.highchat.am/widget/highchat.js"
        data-key="ՁԵՐ-ԲԱՆԱԼԻՆ"
        data-api="https://app.highchat.am" defer></script>

Այս էջը նրանց համար է, ովքեր կառուցում են իրենց ինտերֆեյսը։

Արագ մեկնարկ

Ստեղծեք բանալի «Ալիքներ» → «REST API» բաժնում, ապա ստացեք հոսքային պատասխան.

curl -N https://app.highchat.am/v1/chat \
  -H "Authorization: Bearer hc_xxx" \
  -H "Content-Type: application/json" \
  -d '{"message":"Բարև, ի՞նչ ժամերի եք աշխատում"}'

Նույնականացում

Բոտը ճանաչվում է երկու եղանակներից մեկով։

Ա · API բանալիխորհուրդ է տրվում

Միացրեք «REST API»-ն (կամ «Կայքի վիջեթը») «Ալիքներ» էջում. բանալին ցուցադրվում է մեկ անգամ։ Ուղարկեք այն ամեն հարցումով.

Authorization: Bearer hc_xxxxxxxxxxxxxxxxxxxx

Բանալին հրապարակելի client credential է՝ կապված մեկ բոտի հետ, արագությամբ սահմանափակված, անվտանգ բրաուզերի bundle-ում կամ բջջային հավելվածում (ինչպես վիջեթի բանալին)։ Այն սերվերային գաղտնիք չէ. նրանով հնարավոր չէ կարդալ ձեր վահանակը, գիտելիքը կամ այլ բոտեր։ Ուզում եք բանալին ընդհանրապես չդնել client-ում. անցկացրեք հարցումները ձեր backend-ով (տես օրինակները

Բանալին կարող եք փոխարինել ցանկացած պահի («Ալիքներ» → «Փոխարինել բանալին»). նորը ցուցադրվում է մեկ անգամ, հինը դադարում է աշխատել անմիջապես։

Բ · Հանրային slug (առանց բանալու)

Եթե միացրել եք բոտի «Հանրային զրույցի էջը» («Ալիքներ» էջում), կանչեք նույն endpoint-ները ?slug=your-slug պարամետրով՝ առանց header-ի։ Սա նույն մակերեսն է, որ սպասարկում է highchat.am/c/your-slug էջը։

Հաղորդագրություն ուղարկել — POST /v1/chat

Պատասխանը հոսում է հատված առ հատված՝ Server-Sent Events ձևաչափով։

POST https://app.highchat.am/v1/chat
Authorization: Bearer hc_xxx          # կամ  POST /v1/chat?slug=your-slug  (առանց header-ի)
Content-Type: application/json

{
  "message": "Բարև, ի՞նչ ժամերի եք աշխատում",   // պարտադիր, 1–4000 նիշ
  "conversation_id": "…",                       // ոչ պարտադիր — շարունակել զրույցը
  "visitor_ref": "user-42",                     // ոչ պարտադիր — ձեր օգտատիրոջ ID, ≤200 նիշ
  "customer_email": "…",                        // ոչ պարտադիր — միայն նոր զրույցի առաջին հաղորդագրության հետ
  "customer_phone": "…"                         // ոչ պարտադիր — նույն կանոնով
}

customer_email-ը և customer_phone-ը գրանցվում են միայն նոր զրույց ստեղծելիս (վիջեթի նախազրույցի ձևի դաշտերն են) և հետագայում չեն փոխվում. էլ. հասցեով հաճախորդը փակված զրույցի պատճենն է ստանում, իսկ օպերատորը կարող է պատասխանել նամակով։

Իրադարձությունների հոսք

Պատասխանը text/event-stream է. ամեն իրադարձություն՝ event: <name> + data: <json>.

eventdataինչ անել
meta{ conversation_id }Գալիս է առաջինը։ Պահեք conversation_id և ուղարկեք հաջորդ հարցումով՝ զրույցը շարունակելու համար։
delta{ text }Պատասխանի հատված. ավելացրեք ընթացիկ հաղորդագրությանը։
done{ message_id, state, ts }Պատասխանն ավարտված է։ statebot | pending_human | closed։
human{ message, ts }Զրույցը մարդու մոտ է. բոտը չի պատասխանի։ Ցույց տվեք message-ը, ապա հարցրեք պարբերաբար։
error{ message }Ցույց տվեք օգտատիրոջը. հայերեն, ցուցադրման համար անվտանգ տող է։
ping{}Keepalive։ Անտեսեք։
Սա POST է, որ վերադարձնում է SSE, ուստի բրաուզերի EventSource API-ն (միայն GET) չի աշխատի. կարդացեք response body-ն որպես հոսք, ինչպես օրինակներում։ Նոր զրույց սկսելու համար conversation_id մի ուղարկեք. շարունակելու համար ուղարկեք meta-ից ստացածը։

Օպերատորի փոխանցում

Երբ բոտը փոխանցում է զրույցը (human իրադարձություն կամ done՝ state: pending_human), մարդը պատասխանում է վահանակի «Մուտքարկղ»-ից։ Պատասխանները ստանալու համար հարցրեք պարբերաբար.

GET https://app.highchat.am/v1/conversations/{id}/messages?after={ISO-ts}
Authorization: Bearer hc_xxx          # կամ ?slug=your-slug&after=…
{
  "state": "human",
  "messages": [ { "id":"…", "role":"assistant", "content":"…", "created_at":"2026-06-14T10:00:00.000Z" } ],
  "ts": "2026-06-14T10:00:05.000Z"
}

Վերադարձվում են միայն պատասխանող կողմի (role: assistant) հաղորդագրությունները։ Վերջին created_at-ը փոխանցեք որպես after՝ միայն նորերը ստանալու համար։ Հարցրեք ~4 վայրկյանը մեկ, քանի դեռ statehuman/pending_human է. դադարեցրեք, երբ դառնում է bot կամ closed։

CSAT գնահատական — POST /v1/conversations/{id}/rating

POST https://app.highchat.am/v1/conversations/{id}/rating
Authorization: Bearer hc_xxx
Content-Type: application/json

{ "rating": 1, "comment": "շատ օգտակար էր" }   // 1 = դրական, 0 = բացասական. comment-ը ոչ պարտադիր է, ≤1000 նիշ

Գնահատականները երևում են վահանակի «Վերլուծություն» էջում և որպես զտիչ՝ «Զրույցներ»-ում։

Սխալներ և սահմանափակումներ

Սխալի ձևը մեկն է. message-ը հայերեն, օգտատիրոջը ցուցադրելի տող է.

{ "error": { "code": "rate_limited", "message": "Չափից շատ հաղորդագրություն. փորձեք մեկ րոպեից" } }
HTTPcodeնշանակություն
400invalid_inputդատարկ կամ 4000 նիշից երկար հաղորդագրություն, անվավեր after կամ rating
401unauthenticatedբանալին կամ slug-ը բացակայում է կամ անվավեր է, կամ հանրային էջն անջատված է
403forbidden_originբանալու համար վահանակում նշված են թույլատրված origin-ներ. բրաուզերային հարցումը եկել է այլ կայքից
404not_foundանհայտ զրույց
429rate_limitedսահմանաչափը գերազանցված է. սպասեք և կրկնեք

Սահմանաչափեր. 30 հաղորդագրություն/րոպե՝ մեկ բանալու (բոտի) հաշվով, 15/րոպե՝ մեկ IP-ից։ Հանրային չատի համար կարող է գործել նաև օրական առաստաղ մեկ բոտի հաշվով. գերազանցելիս նույն 429-ն է՝ հայերեն հաղորդագրությամբ։

CORS. /v1-ն ընդունում է ցանկացած origin. կարող եք կանչել ուղիղ բրաուզերից։ Cookie-ներ չեն օգտագործվում։

Օրինակներ

const API = "https://app.highchat.am";
const KEY = "hc_xxx";                 // կամ օգտագործեք ?slug=… և հանեք header-ը
let conversationId = null;

async function send(message, onDelta) {
  const res = await fetch(`${API}/v1/chat`, {
    method: "POST",
    headers: { "content-type": "application/json", authorization: "Bearer " + KEY },
    body: JSON.stringify({ conversation_id: conversationId, message }),
  });
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buf = "", event = "";
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    const lines = buf.split("\n"); buf = lines.pop();
    for (const line of lines) {
      if (line.startsWith("event:")) event = line.slice(6).trim();
      else if (line.startsWith("data:")) {
        const data = JSON.parse(line.slice(5).trim());
        if (event === "meta") conversationId = data.conversation_id;
        else if (event === "delta") onDelta(data.text);
        else if (event === "error") console.error(data.message);
      }
    }
  }
}
function useHighChat(apiKey) {
  const convId = useRef(null);
  const [reply, setReply] = useState("");

  async function send(message) {
    setReply("");
    const res = await fetch("https://app.highchat.am/v1/chat", {
      method: "POST",
      headers: { "content-type": "application/json", authorization: `Bearer ${apiKey}` },
      body: JSON.stringify({ conversation_id: convId.current, message }),
    });
    const reader = res.body.getReader();
    const dec = new TextDecoder();
    let buf = "", ev = "";
    for (;;) {
      const { value, done } = await reader.read();
      if (done) break;
      buf += dec.decode(value, { stream: true });
      const lines = buf.split("\n"); buf = lines.pop();
      for (const l of lines) {
        if (l.startsWith("event:")) ev = l.slice(6).trim();
        else if (l.startsWith("data:")) {
          const d = JSON.parse(l.slice(5).trim());
          if (ev === "meta") convId.current = d.conversation_id;
          else if (ev === "delta") setReply((r) => r + d.text);
        }
      }
    }
  }
  return { reply, send };
}
func send(_ message: String) async throws {
  var req = URLRequest(url: URL(string: "https://app.highchat.am/v1/chat")!)
  req.httpMethod = "POST"
  req.setValue("Bearer hc_xxx", forHTTPHeaderField: "Authorization")
  req.setValue("application/json", forHTTPHeaderField: "Content-Type")
  req.httpBody = try JSONSerialization.data(withJSONObject: [
    "message": message, "conversation_id": conversationId as Any
  ])

  let (bytes, _) = try await URLSession.shared.bytes(for: req)
  var event = ""
  for try await line in bytes.lines {
    if line.hasPrefix("event:") { event = String(line.dropFirst(6)).trimmingCharacters(in: .whitespaces) }
    else if line.hasPrefix("data:") {
      let json = String(line.dropFirst(5)).trimmingCharacters(in: .whitespaces)
      let d = (try? JSONSerialization.jsonObject(with: Data(json.utf8))) as? [String: Any] ?? [:]
      if event == "meta" { conversationId = d["conversation_id"] as? String }
      else if event == "delta" { appendToBubble(d["text"] as? String ?? "") }
    }
  }
}
val body = """{"message":${JSONObject.quote(message)},"conversation_id":${
  conversationId?.let { JSONObject.quote(it) } ?: "null"}}"""
val req = Request.Builder()
  .url("https://app.highchat.am/v1/chat")
  .addHeader("Authorization", "Bearer hc_xxx")
  .post(body.toRequestBody("application/json".toMediaType()))
  .build()

client.newCall(req).execute().use { res ->
  val src = res.body!!.source()
  var event = ""
  while (!src.exhausted()) {
    val line = src.readUtf8Line() ?: break
    when {
      line.startsWith("event:") -> event = line.substring(6).trim()
      line.startsWith("data:")  -> {
        val d = JSONObject(line.substring(5).trim())
        when (event) {
          "meta"  -> conversationId = d.optString("conversation_id")
          "delta" -> appendToBubble(d.optString("text"))
        }
      }
    }
  }
}
// Բանալին պահեք ՁԵՐ սերվերում. հավելվածը խոսում է ձեր backend-ի հետ։
app.post("/chat", async (req, res) => {
  const upstream = await fetch("https://app.highchat.am/v1/chat", {
    method: "POST",
    headers: { "content-type": "application/json",
               authorization: `Bearer ${process.env.HIGHCHAT_KEY}` },
    body: JSON.stringify(req.body),
  });
  res.setHeader("content-type", "text/event-stream");
  upstream.body.pipe(res);   // SSE-ն անցնում է ուղիղ հոսքով
});

Zendesk

HighChat-ը Zendesk-ի հետ աշխատում է երկու տարբերակով։

Ա · Առանց Zendesk-իամենապարզը

Փոքր թիմերի մեծ մասին HighChat-ը բավական է որպես աջակցման ամբողջ համակարգ. բոտը պատասխանում է կայքում, Telegram-ում, WhatsApp-ում, Instagram-ում և Messenger-ում, իսկ այն, ինչ չի կարողանում լուծել, ընկնում է ներկառուցված «Մուտքարկղ», որտեղ մարդը շարունակում է նույն զրույցը։

Բ · Պահեք Zendesk-ը. HighChat-ը պատասխանում է առաջինը

REST API-ն ադապտերն է. Zendesk-ի webhook-ների և POST /v1/chat-ի միջև դրեք ~40 տող middleware։ Բոտը փակում է կրկնվող հարցերը. մնացած զրույցներն անփոփոխ հասնում են ձեր Zendesk օպերատորներին։

// 1. Zendesk Admin Center → Apps & integrations → Webhooks:
//    subscribe to "Comment created" (or a Messaging/Sunshine webhook)
//    pointing at your middleware URL.
// 2. The middleware forwards the visitor's text to HighChat and
//    posts the reply back through the Zendesk API.

app.post("/zendesk-hook", async (req, res) => {
  res.sendStatus(200);                       // ack fast; Zendesk retries otherwise
  const { ticket_id, comment, author_is_end_user } = req.body;
  if (!author_is_end_user) return;           // ignore agent/bot echoes

  const r = await fetch("https://app.highchat.am/v1/chat", {
    method: "POST",
    headers: { "content-type": "application/json",
               authorization: `Bearer ${process.env.HIGHCHAT_KEY}` },
    body: JSON.stringify({
      message: comment,
      conversation_id: store.get(ticket_id),  // keep 1 ticket = 1 conversation
    }),
  });
  const reply = await readSse(r);             // collect `delta` events → full text
  store.set(ticket_id, reply.conversation_id);

  if (reply.escalated) return;                // bot bowed out → leave it to agents
  await fetch(`https://YOURDOMAIN.zendesk.com/api/v2/tickets/${ticket_id}`, {
    method: "PUT",
    headers: { "content-type": "application/json",
               authorization: "Basic " + zendeskAuth },
    body: JSON.stringify({ ticket: { comment: { body: reply.text, public: true } } }),
  });
});

Կարևոր է արտադրական միջավայրում.

Zendesk-ի փորձնական ինտեգրու՞մ եք անում. middleware-ը կկարգավորենք ձեզ հետ միասին — highchat@deployhelp.com։

Հակիրճ տեղեկատու

EndpointAuthնշանակություն
POST /v1/chatբանալի կամ ?slug=հաղորդագրություն ուղարկել, պատասխանը՝ SSE հոսքով
GET /v1/conversations/{id}/messages?after=բանալի կամ ?slug=օպերատորի պատասխանների հարցում
POST /v1/conversations/{id}/ratingբանալի կամ ?slug=CSAT գնահատական (1/0)
GET /v1/p/{slug}առանց authհանրային էջի bootstrap՝ {name, greeting, suggestions}