@aiqa/sdk 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,11 +19,10 @@ A TypeScript/JavaScript SDK for interacting with the AIQA WebSocket service. Thi
19
19
  - [ApplicationVerificationSummary](#applicationverificationsummary)
20
20
  - [ApplicationVerificationStatus](#applicationverificationstatus)
21
21
  - [ApplicationFact](#applicationfact)
22
- - [ApplicationFactInput](#applicationfactinput)
23
22
  - [AddFactResult](#addfactresult)
24
23
  - [VerificationStatus](#verificationstatus)
25
24
  - [FactVerifiedPayload](#factverifiedpayload)
26
- - [FactUpdateEvent](#factupdateevent)
25
+ - [ApplicationFactInput](#applicationfactinput)
27
26
  - [FlagFactResult](#flagfactresult)
28
27
  - [ConversationLanguage](#conversationlanguage)
29
28
  - [UpdateConversationInput](#updateconversationinput)
@@ -77,9 +76,10 @@ new AiQaSdk(applicationId, applicationSecret, url?)
77
76
 
78
77
  - `applicationId: string` - your application id
79
78
  - `applicationSecret: string` - your application secret
80
- - `url?: string` - the AIQA service endpoint. Pass it explicitly: the
81
- built-in fallback is a local development address, so omitting it in a
82
- deployed app connects to `localhost` instead of the service.
79
+ - `url?: string` - the AIQA service endpoint. Always pass it; the default
80
+ only works for local development.
81
+
82
+ The constructor throws if either credential is empty.
83
83
 
84
84
  ## API Reference
85
85
 
@@ -114,8 +114,8 @@ sdk.disconnect();
114
114
 
115
115
  #### `getApplication()`
116
116
 
117
- Returns the application, its conversation participants, and the current
118
- verification tally for the call.
117
+ Returns the application, its conversation participants, and how the call is
118
+ going so far.
119
119
 
120
120
  **Returns:**
121
121
 
@@ -133,10 +133,13 @@ verification tally for the call.
133
133
  }
134
134
  ```
135
135
 
136
- The identity fields are read fresh, so an `updateConversation()` earlier in
137
- the call is reflected. It **rejects** if authentication hasn't completed yet
138
- — wait for the `authenticated` event before calling it — and it rejects on a
139
- failed request rather than quietly handing back older values.
136
+ Wait for the `authenticated` event before calling it: until authentication
137
+ has completed, and whenever the connection is down, it **rejects**.
138
+ `client_name`, `client_phone_number` and `agent_id` normally carry any change
139
+ you made with `updateConversation()` earlier in the call — see
140
+ [Reading `verification`](#reading-verification) for the exception.
141
+ `agent_first_name` and `agent_last_name` come back empty; use
142
+ `updateConversation({ agentName })` if you need to record an agent's name.
140
143
 
141
144
  ```typescript
142
145
  const application = await sdk.getApplication();
@@ -149,27 +152,27 @@ if (application.verification) {
149
152
  }
150
153
  ```
151
154
 
152
- ##### Reading `verification` during a live call
153
-
154
- The summary is computed when you ask for it, so it moves as the call
155
- progresses. Two things to know before you render it:
156
-
157
- - **Most facts start in `count_pending`.** A fact is pending from the moment
158
- you add it until the server reaches a verdict on it, so early in a call
159
- nearly everything sits there and drains into the other counters as the call
160
- proceeds. `count_not_asked` means the question was genuinely never asked; it
161
- does not absorb the ones still in flight.
162
- - **`count_total` is the total, not a pass count.** It is every fact on the
163
- application, verdict or not, so `count_total - count_errors` is _not_ the
164
- number that passed — the pending ones are in there too.
165
- - **`status` only reflects answers.** A skipped question never raises it, so a
166
- call where nothing was asked and nothing was wrong reads `no_errors`. Read
167
- the counters, not just the status, if "incomplete" matters to you.
168
- - **`verification` is absent only against a server that predates it**, in which
169
- case this method returns the identity fields it cached at authentication.
170
- Every other failure — a rejected request, a dropped socket, a server-side
171
- error — rejects instead, so an absent `verification` always means "this
172
- server has no summary to give", never "something went wrong just now".
155
+ ##### Reading `verification`
156
+
157
+ The numbers change during a call. A fact counts as pending from the moment you
158
+ add it until its result arrives, so call `getApplication()` again whenever you
159
+ want current figures.
160
+
161
+ **A fact that was never asked and came back wrong is counted twice: once in
162
+ `count_not_asked` and once in `count_errors`.** That is ordinary, not an edge
163
+ case, and `count_total` also includes every fact that is still pending. So no
164
+ subtraction from `count_total` gives you a reliable number of facts that
165
+ passed. To show one, count the facts whose `verification_status` is `matched`
166
+ in [`getFacts()`](#getfacts).
167
+
168
+ `status` summarises the answers only, so a call where nothing was asked reads
169
+ `no_errors`. Read `count_pending` and `count_not_asked` if your UI cares
170
+ whether the call is complete.
171
+
172
+ `verification` is not always there. When it is missing, there is no summary for
173
+ this call — treat that as unknown rather than as all zeros, and note that
174
+ the identity fields alongside it may then be the ones from when you
175
+ authenticated, without an `updateConversation()` you made since.
173
176
 
174
177
  #### `setConversationProduct(product)`
175
178
 
@@ -229,8 +232,9 @@ change.
229
232
  | `agentGroups` | `string[]` | 32 × 128 | entries cannot contain a comma |
230
233
 
231
234
  Every string (including each `agentGroups` entry) must be non-empty;
232
- surrounding whitespace is trimmed. `null` is rejected — omit the field
233
- instead. At least one field is required.
235
+ surrounding whitespace is trimmed first, so a value of only spaces is
236
+ rejected. `null` is rejected — omit the field instead. At least one field is
237
+ required, and any field not in the table is rejected.
234
238
 
235
239
  **Returns:**
236
240
 
@@ -249,23 +253,23 @@ console.log(result.success, result.conversation.policy_number);
249
253
 
250
254
  #### `addFact(fact)`
251
255
 
252
- Adds a fact to the active application and waits for the **terminal**
253
- verification verdict (Promise-based). The Promise resolves with an
256
+ Adds a fact to the active application and waits for the **final**
257
+ verification result. The Promise resolves with an
254
258
  [`AddFactResult`](#addfactresult); subscribe to the
255
- [`FACT_VERIFIED`](#event-handling) broadcast event to render progress
259
+ [`FACT_VERIFIED`](#event-handling) event to show progress
256
260
  (`awaiting_question`, `awaiting_answer`, `partial`,
257
261
  `pending_confirmation_matched`, `pending_confirmation_unmatched`)
258
262
  while you wait.
259
263
 
260
- `addFact()` does not throw on verification failure — an unmatched
261
- fact resolves with `is_valid_answer: false` and (where the backend
262
- provides it) `verification_status: "unmatched"`.
263
- Reject paths are reserved for transport / protocol errors.
264
+ A failed verification is not an error: an unmatched fact resolves with
265
+ `is_valid_answer: false` and, where present, `verification_status: "unmatched"`.
266
+ The Promise rejects only when the request itself fails — a dropped connection,
267
+ a timeout, a rejected payload.
264
268
 
265
269
  **Returns:**
266
270
 
267
271
  - `Promise<`[`AddFactResult`](#addfactresult)`>` — resolves once the fact
268
- reaches a terminal `verification_status`.
272
+ reaches a final `verification_status`.
269
273
 
270
274
  **Parameters:**
271
275
 
@@ -275,11 +279,10 @@ Reject paths are reserved for transport / protocol errors.
275
279
  id: string;
276
280
  /**
277
281
  * Optional. Stable identifier for the underlying question, shared across
278
- * applications and conversations. When provided it is used to look up (or
279
- * create) the matching question row in the database instead of `id`. When
280
- * omitted, `id` is used (legacy behavior).
282
+ * applications and conversations. When provided it identifies the
283
+ * question instead of `id`. When omitted, `id` is used.
281
284
  *
282
- * Keep this consistent across calls for the "same" question — see
285
+ * Keep it consistent across calls for the "same" question — see
283
286
  * "Question identity and questionId" below.
284
287
  */
285
288
  questionId?: string;
@@ -287,14 +290,12 @@ Reject paths are reserved for transport / protocol errors.
287
290
  expected_answer: any;
288
291
  answer_format: { type: "STRING" }
289
292
  /**
290
- * Optional. Use this to attach your own identifiers to a fact so your UI
291
- * can map the server response back to the right field or component.
292
- * For example, store a form field ID, a section name, or any internal
293
- * reference you need — the server stores it as-is and returns it unchanged
294
- * in getFacts().
293
+ * Optional. Your own identifiers for this fact — a form field ID, a
294
+ * section name, anything that lets your UI map the result back to the
295
+ * right place. getFacts() returns it unchanged.
295
296
  *
296
- * Constraints: all keys and values must be strings; each value is limited
297
- * to 1024 characters. Payloads that exceed this limit are rejected.
297
+ * Keys and values must all be strings, and each value is limited to 1024
298
+ * characters. A payload that breaks either rule is rejected.
298
299
  */
299
300
  metadata?: Record<string, string>
300
301
  }
@@ -311,56 +312,48 @@ const result = await sdk.addFact({
311
312
  });
312
313
 
313
314
  if (result.is_valid_answer) {
314
- // verification_status will be "matched".
315
+ // verification_status, when present, is "matched".
315
316
  console.log("matched:", result.ai_answer);
316
317
  } else {
317
- // verification_status will be "unmatched". matched_components /
318
- // missing_components describe what the partial-match heuristics
319
- // were able to extract.
318
+ // verification_status, when present, is "unmatched". matched_components /
319
+ // missing_components describe which parts of the expected answer
320
+ // were and were not found.
320
321
  console.log("unmatched:", result.missing_components);
321
322
  }
322
323
  ```
323
324
 
324
325
  ##### Question identity and `questionId`
325
326
 
326
- `id` identifies an instance of a fact within a single conversation. `questionId`
327
- is an optional field that identifies the underlying question across every
328
- application and conversation that asks it. They're separated so you can give
329
- each fact instance its own `id` (e.g. a per-call uuid) while still pointing at a
330
- stable question identity.
331
-
332
- Two server-side features are scoped per question identity:
333
-
334
- - **Accuracy improvements.** Per-question signals (flags, model tweaks, fuzzy
335
- matches) accumulate against the question row. Splitting the same logical
336
- question across multiple identities splits these signals and resets the
337
- accuracy gains you've already earned.
338
- - **Remaps from the management dashboard.** When an operator remaps a question
339
- in the dashboard, the remap is stored on the question row. A subsequent call
340
- with a different identity won't pick up the remap.
341
-
342
- The "question identity" the server uses is `questionId` if you sent one,
343
- otherwise `id`. So:
344
-
345
- - If your `id` is already stable across calls for the same logical question,
346
- omitting `questionId` is fine — both features above still work, just keyed off
347
- `id`.
348
- - If your `id` varies per call (per-call uuid, ephemeral instance id, etc.),
349
- send a stable `questionId`. Otherwise each call looks like a new question and
350
- you lose the features above.
351
- - Once you've picked an identity for a question, don't change it. If you must
352
- rename, contact AIQA support first so remaps and historical signals can
353
- be migrated.
327
+ `id` identifies one fact within a single conversation. `questionId` identifies
328
+ the underlying question across every application and conversation that asks it.
329
+ They are separate fields so you can give each fact its own `id` — a per-call
330
+ uuid, say — while still pointing at a stable question.
331
+
332
+ The question identity is `questionId` when you send one, otherwise `id`.
333
+ Anything AIQA has tuned for a question is attached to that identity: the
334
+ corrections that decide how its answers are read, the phrasings that count as
335
+ asking it, the outcome of reviewing facts you flagged. A call that arrives
336
+ under a different identity gets none of it. So:
337
+
338
+ - If your `id` is already stable across calls for the same question, omitting
339
+ `questionId` is fine — the identity is then your `id`.
340
+ - If your `id` varies per call (a per-call uuid, an ephemeral instance id),
341
+ send a stable `questionId`. Otherwise every call looks like a brand-new
342
+ question.
343
+ - Once you have picked an identity for a question, don't change it. If you have
344
+ to rename one, contact AIQA support first so the tuning can move with it.
354
345
 
355
346
  #### `getFacts()`
356
347
 
357
- Retrieves all facts for the application (Promise-based). Each fact includes a `metadata` field containing whatever was passed to `addFact()`. Facts added without `metadata` return `{}`.
348
+ Retrieves every fact on the application, whatever state it is in. Each one
349
+ carries the `metadata` you passed to `addFact()`, or `{}` if you passed none.
350
+ This is also where to count facts by outcome — for a pass count, count the ones
351
+ whose `verification_status` is `matched`.
358
352
 
359
353
  **Returns:**
360
354
 
361
- - `Promise<`[`ApplicationFact[]`](#applicationfact)`>` — every fact of the
362
- application, each with its current `question_status` /
363
- `verification_status`.
355
+ - `Promise<`[`ApplicationFact[]`](#applicationfact)`>` — each fact with its
356
+ current `question_status` and `verification_status`.
364
357
 
365
358
  ```typescript
366
359
  const facts = await sdk.getFacts();
@@ -371,7 +364,7 @@ facts.forEach((fact) => {
371
364
 
372
365
  #### `flagFact(factId)`
373
366
 
374
- Flags a fact for human review. Creates a signal that allow AIQA to improve review quality.
367
+ Flags a fact for human review.
375
368
 
376
369
  **Parameters:**
377
370
 
@@ -436,21 +429,20 @@ Registers an event listener. Call `connect()` before `on()`.
436
429
 
437
430
  **Available Events:**
438
431
 
439
- - `connect` - Socket.IO connection established
440
- - `disconnect` - Socket.IO connection closed
441
- - `close` - Socket.IO connection closed
442
- - `error` - Connection or socket error
443
- - `reconnect_attempt` - Socket.IO reconnection attempt
444
- - `reconnect_error` - Socket.IO reconnection error
445
- - `reconnect_failed` - Socket.IO reconnection failed
446
- - `authenticated` - Local event fired after successful authentication (provides Application object)
447
- - `app_version` - Server event with version requirements `{ min, max }`
448
- - `FACT_VERIFIED` - Broadcast event fired on **every** verification
449
- state transition (both non-terminal progress and terminal verdicts)
450
- for **every** fact in the active conversation. Payload shape:
451
- [`FactVerifiedPayload`](#factverifiedpayload). Use this to render
452
- live verification progress in your UI; `addFact()`'s Promise only
453
- resolves on the terminal state.
432
+ - `connect` - connection established
433
+ - `disconnect` - connection closed
434
+ - `close` - connection closed
435
+ - `error` - connection or socket error
436
+ - `reconnect_attempt` - reconnection attempt
437
+ - `reconnect_error` - reconnection attempt failed
438
+ - `reconnect_failed` - reconnection gave up
439
+ - `authenticated` - authentication succeeded; receives the
440
+ [`Application`](#application)
441
+ - `app_version` - the SDK version range the service supports, `{ min, max }`
442
+ - `FACT_VERIFIED` - fires on **every** verification state change, progress and
443
+ final result alike, for **every** fact in the conversation. Payload:
444
+ [`FactVerifiedPayload`](#factverifiedpayload). Use it to show live progress;
445
+ `addFact()`'s Promise resolves only on the final result.
454
446
 
455
447
  ```typescript
456
448
  sdk.connect();
@@ -468,6 +460,19 @@ sdk.on("FACT_VERIFIED", (payload) => {
468
460
  });
469
461
  ```
470
462
 
463
+ #### `off(eventName, callback?)`
464
+
465
+ Removes an event listener. Omit `callback` to remove every listener
466
+ registered for the event.
467
+
468
+ **Returns:**
469
+
470
+ - `void`
471
+
472
+ ```typescript
473
+ sdk.off("connect");
474
+ ```
475
+
471
476
  ## Verification lifecycle
472
477
 
473
478
  A single `addFact()` call walks through a sequence of states emitted
@@ -479,50 +484,33 @@ processing
479
484
  └─> awaiting_answer (asked, customer hasn't answered yet)
480
485
  └─> partial (partial evidence — e.g. "305" of "30521")
481
486
  └─> pending_confirmation_matched
482
- (backend has a match but is holding a settling
483
- window for mid-answer clarifications like
484
- spellings or "I mean…" corrections)
487
+ (a match is held briefly in case the customer
488
+ corrects it mid-answer — spellings, "I mean…")
485
489
  └─> pending_confirmation_unmatched
486
- (same, but for a held unmatched verdict)
490
+ (same, but for a held unmatched answer)
487
491
  │
488
492
  ▼
489
- matched | unmatched ← terminal
493
+ matched | unmatched ← final
490
494
  ```
491
495
 
492
- Rules for consumers:
496
+ Rules:
493
497
 
494
- - **`addFact()` resolves only on a terminal state** (`matched`,
495
- `unmatched`). Render progress from the
496
- `FACT_VERIFIED` event, render the final verdict from the Promise
497
- result.
498
- - **Treat unknown `verification_status` strings as `processing`.**
499
- The enum is additive — older SDK builds must fall through gracefully
500
- when the backend ships a new state.
501
- - **`pending_confirmation_*` is never terminal.** The wire-visible
502
- latency penalty is bounded by a short server-side settling window
503
- (currently around 2s; not part of the SDK contract). The held verdict
504
- can flip — that's the whole point — so don't treat it as a commit.
505
-
506
- #### `off(eventName, callback?)`
507
-
508
- Removes an event listener. Omit `callback` to remove every listener
509
- registered for the event.
510
-
511
- **Returns:**
512
-
513
- - `void`
514
-
515
- ```typescript
516
- sdk.off("connect");
517
- ```
498
+ - **`addFact()` resolves only on a final state** (`matched`,
499
+ `unmatched`). Show progress from the `FACT_VERIFIED` event, show the final
500
+ result from the Promise.
501
+ - **Handle a `verification_status` you don't recognize as `processing`.**
502
+ - **`pending_confirmation_*` is never final.** The answer can still change,
503
+ so don't show it as a decision.
504
+ - **A fact can be revised after `addFact()` has resolved.** If you keep its
505
+ result on screen for the rest of the call, leave your `FACT_VERIFIED`
506
+ listener attached and always show the latest state for that `factId`.
518
507
 
519
508
  ## Types
520
509
 
521
510
  ### Application
522
511
 
523
512
  Returned by [`getApplication()`](#getapplication): the application, the two
524
- participants of the conversation, and the verification tally at the moment of
525
- the call.
513
+ participants of the conversation, and how the call is going so far.
526
514
 
527
515
  ```typescript
528
516
  type Application = {
@@ -530,9 +518,10 @@ type Application = {
530
518
  client_name: string;
531
519
  client_phone_number: string;
532
520
  agent_id: string;
533
- agent_first_name: string;
534
- agent_last_name: string;
535
- // Absent on servers that predate this field.
521
+ agent_first_name: string; // comes back empty
522
+ agent_last_name: string; // comes back empty
523
+ // Missing when there is no summary for the call — not the same as zeros.
524
+ // See "Reading verification" above.
536
525
  verification?: ApplicationVerificationSummary;
537
526
  };
538
527
  ```
@@ -546,40 +535,42 @@ type ApplicationVerificationSummary = {
546
535
  // Facts whose answer did not match the expected one.
547
536
  count_errors: number;
548
537
 
549
- // Subset of count_errors whose question is marked critical.
538
+ // The facts in count_errors that you sent with critical: true.
550
539
  count_critical_errors: number;
551
540
 
552
- // Every fact on the application, verdict or not. Neither a pass count nor a
553
- // count of what has been evaluated: the two counters below are subsets of
554
- // it, not separate buckets.
541
+ // Every fact on the application, checked or not. The other counters are
542
+ // subsets of it and can overlap each other, so no subtraction from
543
+ // count_total gives you a pass count.
555
544
  count_total: number;
556
545
 
557
- // Facts whose question was genuinely never asked. Does not include the ones
558
- // still awaiting a verdict — those are count_pending.
546
+ // Facts whose question was never asked. Does not include the ones still
547
+ // waiting for a result — those are count_pending. It does overlap
548
+ // count_errors: a fact never asked that came back wrong is in both.
559
549
  count_not_asked: number;
560
550
 
561
- // Subset of count_not_asked whose question is marked critical.
551
+ // The facts in count_not_asked that you sent with critical: true.
562
552
  count_critical_not_asked: number;
563
553
 
564
554
  // Facts added but not yet resolved. Most of the call's facts sit here early
565
- // on and drain as verdicts land.
555
+ // on and move out as their results arrive.
566
556
  count_pending: number;
567
557
 
568
- // Facts the conduct review flagged. Independent of the answer verdict — a
569
- // matched fact can still be suspicious.
558
+ // Facts flagged as suspicious when the call is reviewed — for instance the
559
+ // agent leading the customer to the expected answer. Independent of the
560
+ // answer: a matched fact can be flagged. Reads 0 while the call is running.
570
561
  count_suspicious: number;
571
562
  };
572
563
  ```
573
564
 
574
565
  ### ApplicationVerificationStatus
575
566
 
576
- Rolled-up verdict over the answers, for the whole application. Distinct from
567
+ Overall result for the whole call, based on the answers. Distinct from
577
568
  [`VerificationStatus`](#verificationstatus), which describes a single fact.
578
569
  Questions that were never asked do not raise it.
579
570
 
580
571
  ```typescript
581
572
  type ApplicationVerificationStatus =
582
- // At least one critical fact failed.
573
+ // At least one fact you sent with critical: true failed.
583
574
  | "critical_errors"
584
575
  // At least one fact failed, none of them critical.
585
576
  | "errors"
@@ -589,7 +580,7 @@ type ApplicationVerificationStatus =
589
580
 
590
581
  ### ApplicationFact
591
582
 
592
- Returned by `getFacts()`. Extends `ApplicationFactInput` and adds server-side fields.
583
+ Returned by `getFacts()`. Extends `ApplicationFactInput` with the fields the service fills in.
593
584
 
594
585
  ```typescript
595
586
  type ApplicationFact = ApplicationFactInput & {
@@ -597,13 +588,14 @@ type ApplicationFact = ApplicationFactInput & {
597
588
  question_status: "searching" | "asked" | "not_asked";
598
589
  verification_status: VerificationStatus;
599
590
  flagged: boolean; // true once flagFact() has been called for this fact
600
- metadata: Record<string, string>; // always present; {} when not set on addFact
591
+ // metadata is inherited from ApplicationFactInput, where it is optional.
592
+ // getFacts() always fills it in: {} for a fact you added without one.
601
593
  };
602
594
  ```
603
595
 
604
596
  ### AddFactResult
605
597
 
606
- Resolved value of `addFact()`. Only emitted at the terminal verification
598
+ Resolved value of `addFact()`. Only sent once the fact reaches its final
607
599
  state — see [Verification lifecycle](#verification-lifecycle).
608
600
 
609
601
  ```typescript
@@ -621,23 +613,20 @@ interface AddFactResult {
621
613
  question_asked?: boolean;
622
614
 
623
615
  /**
624
- * 0–1 (or 0–100 — scale matches the configured similarity method).
625
- * Similarity between the agent's utterance and the expected question.
616
+ * How closely the agent's utterance matched the expected question, on a
617
+ * 0–1 or a 0–100 scale. Higher is closer.
626
618
  */
627
619
  question_match_score?: number;
628
620
 
629
621
  /**
630
- * 0–1 score derived from how well the customer's answer matched expected.
631
- * Derived from partial-match heuristics (numeric-prefix ratio,
632
- * matched-components ratio).
622
+ * 0–1 score for how closely the customer's answer matched the expected one.
623
+ * Undefined when there is no partial signal to score.
633
624
  */
634
625
  answer_match_score?: number;
635
626
 
636
627
  /**
637
- * Top-level state at terminal resolution. Always one of `matched`
638
- * or `unmatched` because the `addFact()` Promise only
639
- * resolves on terminals. Optional for compatibility with older
640
- * server versions.
628
+ * The final state: `matched` or `unmatched` whenever it is present.
629
+ * Fall back to `is_valid_answer` when it is missing.
641
630
  */
642
631
  verification_status?: VerificationStatus;
643
632
 
@@ -667,16 +656,15 @@ type VerificationStatus =
667
656
  | "unmatched";
668
657
  ```
669
658
 
670
- The enum is additive: consumers that `switch` on this value MUST
671
- treat unknown strings as `"processing"` so older SDK builds keep
672
- working after the backend ships a new state. See the
673
- [Verification lifecycle](#verification-lifecycle) for the transitions
674
- and which states are terminal.
659
+ Code that `switch`es on this value must treat any string it doesn't
660
+ recognize as `"processing"`. See the
661
+ [Verification lifecycle](#verification-lifecycle) for the transitions and
662
+ which states are final.
675
663
 
676
664
  ### FactVerifiedPayload
677
665
 
678
- Payload of the `FACT_VERIFIED` broadcast event. Same shape as
679
- `AddFactResult` plus the `factId` / `success` / `error` envelope.
666
+ Payload of the `FACT_VERIFIED` event: which fact the update is about, its
667
+ current state, and the full [`AddFactResult`](#addfactresult) shape in `data`.
680
668
 
681
669
  ```typescript
682
670
  interface FactVerifiedPayload {
@@ -687,7 +675,7 @@ interface FactVerifiedPayload {
687
675
  answer_match_score?: number;
688
676
  matched_components?: string[];
689
677
  missing_components?: string[];
690
- /** Same shape as AddFactResult so the same renderer handles both. */
678
+ /** Inner payload, same shape as AddFactResult. */
691
679
  data?: AddFactResult;
692
680
  error?: string;
693
681
  }
@@ -700,12 +688,12 @@ type ApplicationFactInput = {
700
688
  id: string;
701
689
  /**
702
690
  * Optional. Stable identifier for the underlying question, shared across
703
- * applications and conversations. Used to look up (or create) the matching
704
- * question row in the database when provided. When omitted, `id` is used.
691
+ * applications and conversations. When provided it identifies the question
692
+ * instead of `id`. When omitted, `id` is used.
705
693
  *
706
- * Keep this consistent across calls — accuracy improvements and remaps
707
- * configured in the management dashboard are scoped per `questionId`. See
708
- * "Question identity and questionId" under `addFact()`.
694
+ * Keep it consistent across calls: whatever AIQA has tuned for a question is
695
+ * attached to this identity. See "Question identity and questionId" under
696
+ * `addFact()`.
709
697
  */
710
698
  questionId?: string;
711
699
  question: string;
@@ -726,21 +714,18 @@ type ApplicationFactInput = {
726
714
  category_id?: string;
727
715
  category_name?: string;
728
716
  language?: string;
717
+ // Mark the question critical: its failures land in count_critical_errors,
718
+ // and one of them sets status to "critical_errors".
729
719
  critical?: boolean;
730
720
  is_skipped?: boolean;
731
721
  /**
732
- * Optional. Attach your own identifiers to a fact so your UI can map the
733
- * server response back to the right field or component — for example a form
734
- * field ID, a section name, or any internal reference you need.
722
+ * Optional. Your own identifiers for this fact — a form field ID, a section
723
+ * name, anything that lets your UI map the result back to the right place.
724
+ * getFacts() returns it unchanged (as {} for a fact you added without one),
725
+ * and it plays no part in verification.
735
726
  *
736
- * The server stores this value encrypted alongside the fact and returns it
737
- * unchanged in getFacts(). It is never inspected, indexed, or used for
738
- * verification logic.
739
- *
740
- * Constraints:
741
- * - All keys and values must be strings.
742
- * - Each individual value is limited to 1024 characters.
743
- * - Payloads that violate either constraint are rejected by the server.
727
+ * Keys and values must all be strings, and each value is limited to 1024
728
+ * characters. A payload that breaks either rule is rejected.
744
729
  */
745
730
  metadata?: Record<string, string>;
746
731
  };
@@ -810,25 +795,6 @@ type UpdateConversationResult = {
810
795
  };
811
796
  ```
812
797
 
813
- ### FactUpdateEvent
814
-
815
- ```typescript
816
- type FactUpdateEvent = {
817
- fact_id: string;
818
- question_id?: string;
819
- status:
820
- | "asked"
821
- | "answered_detected"
822
- | "agent_answered"
823
- | "verification_pending"
824
- | "verified"
825
- | "failed";
826
- detectedAnswer?: any;
827
- agentAnswer?: any;
828
- verifiedAnswer?: any;
829
- };
830
- ```
831
-
832
798
  ## Examples
833
799
 
834
800
  ### Complete Example: Recording Session
@@ -845,8 +811,9 @@ const sdk = new AiQaSdk(
845
811
 
846
812
  sdk.connect();
847
813
 
848
- sdk.on("connect", async () => {
849
- console.log("Connected!");
814
+ // getApplication() is only available once authentication has completed.
815
+ sdk.on("authenticated", async () => {
816
+ console.log("Authenticated!");
850
817
 
851
818
  try {
852
819
  const application = await sdk.getApplication();
@@ -864,7 +831,7 @@ sdk.on("connect", async () => {
864
831
  );
865
832
  });
866
833
 
867
- // Add a fact (Promise resolves at the terminal verdict)
834
+ // Add a fact (the Promise resolves once verification finishes)
868
835
  const result = await sdk.addFact({
869
836
  id: "q1",
870
837
  question: "What is your name?",
@@ -875,7 +842,7 @@ sdk.on("connect", async () => {
875
842
  });
876
843
 
877
844
  console.log(
878
- "Terminal verdict:",
845
+ "Final result:",
879
846
  result.verification_status,
880
847
  "is_valid_answer:",
881
848
  result.is_valid_answer,
@@ -911,14 +878,15 @@ try {
911
878
 
912
879
  ### Common Error Scenarios
913
880
 
914
- 1. **Connection Errors**: Fired through the `error` event
915
- 2. **Version Mismatch**: Thrown when the server version is incompatible
916
- 3. **Invalid Data**: Returned as rejected promises
917
- 4. **Network Issues**: Handled through reconnection events
881
+ 1. **Connection errors** - reported through the `error` event.
882
+ 2. **Unsupported SDK version** - the SDK disconnects and reports it through
883
+ the `error` event.
884
+ 3. **Invalid data** - the method's Promise rejects.
885
+ 4. **Network drops** - reported through the `reconnect_*` events.
918
886
 
919
887
  ## Version Requirements
920
888
 
921
- The server emits an `app_version` payload with `{ min, max }` supported SDK versions. If the current SDK version is outside that range, the SDK disconnects and emits an `error` event.
889
+ If your SDK version is outside the range the service supports, the SDK disconnects and emits an `error` event. The supported range arrives on the `app_version` event as `{ min, max }`.
922
890
 
923
891
  ## License
924
892