# STT Audit Ingestion Guide

This guide explains how to integrate the SDK STT audit ingestion flow that posts the final session audit to an HTTP endpoint when `stopTranscription()` runs.

## Overview

The SDK can automatically send the final audit payload at the end of a Whisper session.

- Trigger: `stopTranscription()` only
- Provider scope: Whisper providers (`sofya_as_service`, `sofya_whisper_flow`, `stt_wvad`)
- Default endpoint path: `/v1/stt/audits`
- Failure behavior: non-blocking for `stopTranscription()` (warning event + `console.warn`)
- Retries: transient failures only (network errors and HTTP `5xx`)

## 1) Enable the Feature

Configure `auditIngestion` in `SofyaSpeechConfig`.

```ts
import { createTranscriber } from "sofya.transcription";

const transcriber = createTranscriber({
  provider: "sofya_as_service",
  endpoint: "wss://scribe.sofya.health/api/realtime",
  config: {
    language: "en-US",
    external_id: "visit-12345",
    token: "jwt-token", // optional bearer source
    headers: {
      "x-api-key": "YOUR_API_KEY", // required for ingestion
      "x-terminal-id": "TERM-001",
      "x-app-version": "3.2.1",
    },
    auditIngestion: {
      // Optional. Defaults to /v1/stt/audits.
      endpoint: "/v1/stt/audits",
      // Optional request body overrides:
      threadId: "2b9c38bc-31f5-4fd0-b8f0-e796ee8d7ee8",
      externalIdentifier: "visit-12345",
      // Optional per-endpoint header overrides/additions:
      headers: {
        "x-app-version": "3.2.2-hotfix",
      },
    },
    debug: {
      enabled: true,
      metadata: {
        thread_id: "2b9c38bc-31f5-4fd0-b8f0-e796ee8d7ee8",
      },
    },
  },
});
```

## 2) Understand Dispatch Timing

In `stopTranscription()` flow, ingestion runs:

1. after stop finalization and audit stop marker
2. after telemetry vendor dispatch (`telemetry`)
3. before optional `downloadDebugAudit()` auto-download cleanup

It is awaited, but ingestion failures do not reject `stopTranscription()`.

## 3) Request Construction Rules

### URL resolution

- Base URL uses the resolved realtime host converted to HTTP(S) base (same pattern as batch reprocess host reuse)
- Endpoint is:
  - `auditIngestion.endpoint` when provided (absolute or relative), otherwise
  - default `/v1/stt/audits`

### Header resolution

Headers are built in this order:

1. inherited connection headers (`config.headers`)
2. `auditIngestion.headers` overrides
3. `Authorization: Bearer <token>` injected if token exists and Authorization is not already set
4. `Content-Type: application/json` is forced

Minimal precheck:

- `x-api-key` must exist (case-insensitive)
- if missing, request is skipped and warning `missing_api_key` is emitted

### Body contract

The SDK sends:

```json
{
  "thread_id": "optional",
  "external_identifier": "optional",
  "stt_session_ids": ["optional"],
  "audit": { "... full raw audit object ..." }
}
```

`audit` is sent unchanged (raw output from `getDebugAudit()`).

`stt_session_ids` lists the server `session_id` values (surfaced through the `stt_session` event) for every realtime connection of the run (reconnections included), in order. Each id names one recording on the server side. The field is omitted when the server did not send any `session_id` (older servers).

Identifier precedence:

- `thread_id`
  1. `auditIngestion.threadId`
  2. `audit.metadata.thread_id`
  3. `audit.metadata.threadId`
- `external_identifier`
  1. `auditIngestion.externalIdentifier`
  2. resolved realtime `external_id` (`config.external_id`)
  3. `audit.metadata.external_identifier`
  4. `audit.metadata.externalIdentifier`
  5. `audit.metadata.external_id`

## 4) Failure and Retry Behavior

Retries:

- Initial attempt + 2 retries
- Backoff delays: `300ms`, then `600ms`
- Retryable failures:
  - network/fetch failure
  - HTTP `5xx`
- Not retried:
  - HTTP `4xx`
  - missing `x-api-key`

Warning event payload (`stt_audit_ingestion_warning`) includes:

- `code`: `missing_api_key` | `fetch_unavailable` | `invalid_endpoint` | `http_error` | `network_error` | `dispatch_failed`
- `message`
- optional `status`, `attempt`, `endpoint`, `detail`

## 5) Subscribe to Warnings

```ts
transcriber.on("stt_audit_ingestion_warning", (warning) => {
  // Recommended: forward to app logger/Sentry
  console.warn("STT audit ingestion warning", warning);
});
```

## 6) Backend Contract Checklist

Expected server side contract:

- method: `POST`
- content type: `application/json`
- required header: `x-api-key`
- endpoint: `/v1/stt/audits` (or your configured override)
- body fields: `audit` required, `thread_id` optional, `external_identifier` optional, `stt_session_ids` optional

## 7) Validation Checklist (Client)

- Use a Whisper provider
- Configure `auditIngestion` block
- Ensure `x-api-key` is present in merged headers
- Ensure CORS allows your browser origin and headers
- Call `await stopTranscription()`
- Watch `stt_audit_ingestion_warning` for operational visibility

## 8) Operational Notes

- The feature does not run on `error`/`disconnected`; only on stop
- The feature is designed to be safe for UI shutdown flows (non-blocking error contract)
- Keep `thread_id` and `external_identifier` stable to simplify backend correlation and idempotent upserts
