Metadata-Version: 2.5
Name: archeai-sdk
Version: 0.3.2
Summary: Official Python SDK for the ArcheAI behavioral intelligence API — executive behavioral histories, deception-relevant signals, personality, and communication-style analytics from speech.
Project-URL: Homepage, https://arche-ai.com
Project-URL: Documentation, https://pypi.org/project/archeai-sdk/
Project-URL: API Reference, https://api.arche-ai.com/docs/
Project-URL: Source, https://arche-ai.com
Author-email: ArcheAI <contact@arche-ai.com>
License: MIT
Keywords: alternative-data,behavioral-analytics,earnings-calls,nlp,quantitative-finance,voice-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.9
Requires-Dist: requests>=2.28
Provides-Extra: pandas
Requires-Dist: pandas>=1.5; extra == 'pandas'
Description-Content-Type: text/markdown

# archeai-sdk

Official Python SDK for the [ArcheAI](https://arche-ai.com) behavioral
intelligence API — executive behavioral histories, multi-speaker session
analysis, deception-relevant signals, personality, and communication-style
analytics from speech.

```bash
pip install "archeai-sdk[pandas]"
```

## Documentation

The complete reference is inlined below (PyPI-hosted copy of the SDK docs; same content as the package's `docs/` folder and every method's docstring).

| | |
|---|---|
| [Getting started](#getting-started) | install, auth, the three request shapes, which method to use, credits, trials, data handling |
| [Quant: behavioral history](#quant) | `behavioral_history()` — every parameter and every output column |
| [Text analyses](#text) | fraud-language, personality, style, batch — parameters + result fields |
| [Audio (single speaker)](#audio) | upload, deception, voice personality, pair, convergence, one-call flow |
| [Sessions (multi-speaker)](#sessions) | `analyze_session()` — diarization + per-speaker scores + time series, PHI mode |
| [Jobs, account, models](#jobs) | polling, credits, model catalog |
| [Interpreting scores](#interpreting-scores) | what z-scores, 1–7 traits, and 0–1 signals mean — and their limits |
| [Errors](#errors) | every error code and what to do |

Every public method also carries the same documentation in its docstring
(`help(ArcheClient.analyze_session)`), and the REST API's own reference is
at [api.arche-ai.com/docs](https://api.arche-ai.com/docs).

## 30-second tour

```python
from arche_ai import ArcheClient
c = ArcheClient(api_key="arche_sk_...")

# Quant: one row per (executive, quarter), point-in-time safe
df = c.behavioral_history("AAPL", from_q="2018Q1")

# Text: async job -> wait -> result dict
style = c.wait(c.analyze_style(exec_answers)).result

# Single-speaker clip: upload -> analyze -> wait -> (delete), one call
out = c.analyze_file("clip.wav", lines=("deception", "voice-personality"),
                     delete_after=True)

# Multi-speaker recording: diarize + transcribe + per-speaker scores
sess = c.analyze_session("interview.wav", phi=True)   # HIPAA-mode example
sess.speaker_frame()      # per-speaker Big Five + style
sess.segment_frame()      # per-speaker behavioral time series
```

## Quant quickstart

```python
from arche_ai import ArcheClient

c = ArcheClient(api_key="arche_sk_...")

# Flagship: per-executive quarterly behavioral trajectories, from
# ArcheAI's 1.8M-earnings-call research corpus (2005-present).
# Point-in-time safe: each quarter's scores derive only from that
# quarter's calls; history is append-only — safe for backtests.
df = c.behavioral_history("AAPL", from_q="2018Q1")
#   one row per (executive, quarter):
#   7 communication-style z-scores + Big Five estimates

# Example: flag executives breaching their own uncertainty baseline
pivot = df.pivot_table(index="quarter", columns="executive",
                       values="style_uncertain_certain")
z = (pivot - pivot.expanding().mean()) / pivot.expanding().std()
print(z.tail(4))  # who no longer sounds like themselves?
```

These are the same measures behind ArcheAI's published event-study
results (out-of-sample lift over price, Loughran-McDonald sentiment,
and SUE baselines at 1–5 day horizons).

## Text analyses (async jobs)

```python
job = c.analyze_fraud_language(qa_transcript_text)  # >= 200 chars
job = c.analyze_personality(text)
job = c.analyze_style(text)

result = c.wait(job)          # poll to completion
print(result.result)
```

## Audio (bring your own recordings)

```python
audio_id = c.upload_audio("interview.wav")   # one call: 3-step flow
job = c.analyze_deception_audio(audio_id)    # research signal
job = c.analyze_voice_personality(audio_id)  # voice-only Big Five
final = c.wait(job)
```

Uploaded audio is automatically deleted from storage after 7 days;
delete sooner via the API or your account's My Data page.

## Utilities

```python
c.models()    # available models + per-call credit costs
c.account()   # remaining credits
```

## Important framing

All scores are **research signals intended to inform professional
judgment** — not investment advice, accusations, lie detection, or
determinations of fact. Validation methodology, published nulls, and
boundary conditions are documented at
[api.arche-ai.com/docs](https://api.arche-ai.com/docs).

## Roadmap

- Speaker identification against ArcheAI's executive voiceprint
  database (`speakers="auto"`)
- Bulk/point-in-time history export for backtesting
- Event-study starter kit (reproduce our published results on your
  own universe)

© ArcheAI. Contact: contact@arche-ai.com


---

# Reference

<a id="getting-started"></a>

## Getting started

```bash
pip install archeai-sdk            # core (requests only)
pip install "archeai-sdk[pandas]"  # DataFrame outputs
```

```python
from arche_ai import ArcheClient
c = ArcheClient(api_key="arche_sk_...")        # from the web app → Settings → API Keys
c.account()                                     # {"credits": ..., "trial": {...}?}
```

`ArcheClient(api_key, base_url="https://api.arche-ai.com", dataframes=True, timeout=60.0)`

| arg | meaning |
|---|---|
| `api_key` | Workspace-scoped key. Credits are deducted from the key's **workspace**. |
| `base_url` | Override for staging. |
| `dataframes` | Return pandas DataFrames where natural; `False` → lists of dicts. Degrades gracefully if pandas isn't installed. |
| `timeout` | Per-request HTTP timeout in seconds. |

### The three shapes of request

1. **Synchronous reads** — `behavioral_history()`, `account()`, `models()`, `audio_status()`. Return immediately.
2. **Async analysis jobs** — every `analyze_*` method returns a `Job` (`status="queued"`). Credits are deducted at submission. Poll with `wait(job)`; the finished `Job.result` is a dict whose fields are documented per method.
3. **One-call conveniences** — `analyze_file()` (single-speaker clip) and `analyze_session()` (multi-speaker recording) do upload → analyze → wait → assemble for you.

```python
job = c.analyze_style(text)        # queued, credits deducted
done = c.wait(job)                  # polls until completed/failed
done.result["dimensions"]["uncertain_certain"]["score"]
```

### Which method do I want?

| I have… | Use |
|---|---|
| A ticker and want executive behavior over time | `behavioral_history("AAPL")` |
| Text from one person | `analyze_fraud_language` / `analyze_personality` / `analyze_style` |
| Many texts | `analyze_texts(line, texts)` |
| A clip of one speaker | `analyze_file(path)` → deception + voice personality |
| Two clips of the **same** speaker | `upload_audio` ×2 → `analyze_deception_pair` |
| Two clips of **different** speakers | `upload_audio` ×2 → `analyze_convergence` |
| A recording with several speakers (interview, session, meeting) | `analyze_session(path)` |
| Protected health information | `analyze_session(path, phi=True)` inside a BAA-covered workspace |

### Credits (per call, as of SDK 0.3)

| call | credits |
|---|---|
| text analyses | 1 each |
| behavioral_history | 5 |
| single-clip audio lines | 10 each |
| session | 40 (includes vendor transcription) |

`models()` is authoritative — costs live in the model registry, not the SDK.

### Trials

Trial workspaces may be restricted to a ticker allow-list, a rolling history
window, a daily request cap, and an expiry. `account()["trial"]` shows the
terms; `behavioral_history()` sets `client.last_trial`; boundary errors
raise `ArcheAPIError` with `.is_trial_limit == True`
(`TRIAL_TICKER_DENIED`, `TRIAL_DAILY_CAP`, `TRIAL_EXPIRED`). See
[errors.md](errors.md).

### Data handling

- Uploaded audio auto-deletes after **7 days**; `delete_audio()` / `delete_after=True` deletes immediately.
- Text you submit is processed and not retained beyond the job record.
- PHI: use `analyze_session(..., phi=True)` — transcript PII/PHI redaction + vendor-side purge. See [sessions.md](sessions.md).
- No LLM is used in any analysis line.

<a id="quant"></a>

## Quant: behavioral history

Point-in-time executive behavioral trajectories from the research corpus.

_All scores are research signals intended to inform professional judgment — not diagnoses, accusations, lie detection, or determinations of fact._

#### `behavioral_history()`

Per-executive quarterly behavioral trajectories for a public company.

The flagship quant endpoint (`GET /v1/companies/{ticker}/behavioral-history`):
for every executive who has spoken on the company's earnings calls, one row
per quarter with 7 communication-style dimensions and Big Five estimates,
computed only from that quarter's calls. History is append-only, so it is
safe for point-in-time backtests.

**Args**

```text
    ticker: Exchange ticker, e.g. `"AAPL"`. Case-insensitive. Must exist
        in the research corpus (~19.7K companies).
    from_q: Earliest quarter, `"YYYYQn"` (e.g. `"2018Q1"`). `None` =
        start of history (2005). On a trial workspace the trial's history
        floor overrides an earlier value.
    to_q: Latest quarter, `"YYYYQn"`. `None` = latest available.
```

**Returns**

```text
    `pandas.DataFrame` (list of dicts without pandas), one row per
    (executive, quarter):

    - `ticker`, `speaker_id` (int), `executive` (name or None)
    - `quarter` (`"2024Q1"`), `n_calls`, `n_words` — how much speech
      the quarter's scores rest on (more words = more stable)
    - `style_<dim>` — z-scores vs executive-register norms for
      intellectual_colloquial, concrete_abstract, tentative_assertive, authority_people, formal_conversational, uncertain_certain, pessimistic_optimistic. Positive = toward the second pole.
    - `big5_<trait>` — `openn`, `consc`, `extra`, `agree`,
      `neuro` on a 1-7 scale.

    After the call `client.last_trial` holds `{label, historyFrom,
    expiresAt}` for trial workspaces, else `None`.

Costs 5 credits per call.
```

**Raises**

```text
    ArcheAPIError: `NOT_FOUND` (ticker not in corpus),
        `INSUFFICIENT_CREDITS`, `FORBIDDEN`, or a trial code
        (`TRIAL_TICKER_DENIED` / `TRIAL_DAILY_CAP` / `TRIAL_EXPIRED`;
        see `ArcheAPIError.is_trial_limit`).
```

<a id="text"></a>

## Text analyses

Single-speaker text → fraud-language, personality, communication style. Async jobs.

_All scores are research signals intended to inform professional judgment — not diagnoses, accusations, lie detection, or determinations of fact._

#### `analyze_fraud_language()`

Fraud-language screening score for a text (`POST /v1/analyses/fraud-language`).

Mixture-of-experts score trained on SEC-enforcement-era executive speech
(AUC 0.874 on a frozen holdout). A research screening signal — never an
accusation or determination of fact.

**Args**

```text
    text: Unscripted speech or writing by ONE person (an executive's Q&A
        answers, an interview transcript, an essay). Minimum ~50 words;
        the models are calibrated on hundreds+. Scripted or multi-speaker
        text degrades validity.
```

**Returns**

```text
    `Job` with `status="queued"`. Pass it to `wait()`; the
    completed job's `.result` dict has the fields below.

    - `score` (0-1): higher = more similar to enforcement-era speech
    - `experts`: `{lexical, embedding, deviation}` component
      probabilities; `deviation` is `None` for one-shot texts (the
      within-speaker baseline expert needs speaker history)
    - `n_words`, `notes`, `model_version`, `disclaimer`
    - `holdout_auc`: frozen-holdout AUC of the serving model version
      (context for the score, not a per-text confidence)
```

**Raises**

```text
    ArcheAPIError: `BAD_REQUEST` if the text is too short.
```

#### `analyze_personality()`

Big Five personality estimate from language (`POST /v1/analyses/personality`).

Distilled from a psychologist-reference panel (r .92-.96 vs reference on
held-out speakers). Measures *expressed* personality; not a clinical
instrument.

**Args**

```text
    text: Unscripted speech or writing by ONE person (an executive's Q&A
        answers, an interview transcript, an essay). Minimum ~50 words;
        the models are calibrated on hundreds+. Scripted or multi-speaker
        text degrades validity.
```

**Returns**

```text
    `Job` with `status="queued"`. Pass it to `wait()`; the
    completed job's `.result` dict has the fields below.

    - `traits`: `{openness, conscientiousness, extraversion,
      agreeableness, neuroticism}` each on a **1-7** scale
    - `confidence`: `"low"` (<200 words), `"medium"` (200-599),
      `"good"` (600-1999), `"high"` (>=2000) — estimates converge as
      text volume grows
    - `n_words`, `confidence_note`, `model_version`, `disclaimer`
```

#### `analyze_style()`

7-dimension communication style vs executive-register norms (`POST /v1/analyses/style`).

**Args**

```text
    text: Unscripted speech or writing by ONE person (an executive's Q&A
        answers, an interview transcript, an essay). Minimum ~50 words;
        the models are calibrated on hundreds+. Scripted or multi-speaker
        text degrades validity.
```

**Returns**

```text
    `Job` with `status="queued"`. Pass it to `wait()`; the
    completed job's `.result` dict has the fields below.

    - `dimensions`: for each of intellectual_colloquial, concrete_abstract, tentative_assertive, authority_people, formal_conversational, uncertain_certain, pessimistic_optimistic →
      `{score, label, component_coverage}`. `score` is a z-score vs
      executive norms (positive = toward the second pole in the name, e.g.
      +1.0 on `uncertain_certain` = more certain than typical executives);
      `component_coverage` (0-1) = share of the dimension's lexical
      components present in the text.
    - `units`, `norms`, `n_words`, `confidence`, `model_version`,
      `disclaimer`
```

#### `analyze_texts()`

Submit many texts on one analysis line and wait for all (batch helper).

**Args**

```text
    line: `"fraud-language"` | `"personality"` | `"style"`.
    texts: Texts (one speaker each; see the single-text methods for
        minimum lengths).
    timeout: Max seconds to wait per job.
```

**Returns**

```text
    list of result dicts in input order (schema per the matching
    `analyze_*` method); `None` for a job that failed.
```

<a id="audio"></a>

## Audio analyses (single speaker)

Upload a clip of ONE speaker → vocal deception indicators, voice personality, within-speaker pair comparison, cross-speaker convergence.

_All scores are research signals intended to inform professional judgment — not diagnoses, accusations, lie detection, or determinations of fact._

#### `upload_audio()`

Upload a local audio file for analysis (3-step signed-URL flow in one call).

`POST /v1/audio` → `PUT` bytes directly to cloud storage →
`POST /v1/audio/{id}/confirm`. Bytes never transit the API gateway.

**Args**

```text
    path: Local file. WAV, MP3, M4A, FLAC, OGG accepted (decoded
        server-side to 16 kHz mono).
    content_type: MIME type matching the bytes: `"audio/wav"`,
        `"audio/mpeg"`, `"audio/mp4"`, `"audio/flac"`, `"audio/ogg"`.
```

**Returns**

```text
    `audioId` (str, UUID) for the `analyze_*` audio methods.

Audio auto-deletes **7 days** after upload, or immediately via
`delete_audio()`. Uploading costs no credits.
```

#### `analyze_deception_audio()`

Deception-relevant vocal indicators for ONE speaker's clip (`POST /v1/analyses/deception`).

88 eGeMAPS acoustic features → model validated on incentivized
revealed-truth corpora. Best with >=10 s of continuous speech from one
speaker. Probabilistic screening signal, NOT a lie detector.

**Args**

```text
    audio_id: `audioId` returned by `upload_audio()` (status must be
        `uploaded`).
```

**Returns**

```text
    `Job`; after `wait()`, `.result` has:

    - `score` (0-1): higher = more deception-consistent vocal pattern
    - `n_seconds`: audio duration scored
    - `notes`, `model_version`, `disclaimer`

Costs 10 credits.
```

#### `analyze_voice_personality()`

Big Five from the voice alone, no transcript (`POST /v1/analyses/voice-personality`).

Verification-grade (r .33-.41 on held-out speakers — top of the published
voice→personality literature); use alongside the text personality line,
not instead of it. Several minutes of one speaker is ideal.

**Args**

```text
    audio_id: `audioId` returned by `upload_audio()` (status must be
        `uploaded`).
```

**Returns**

```text
    `Job`; after `wait()`, `.result` has:

    - `traits`: `{openness, conscientiousness, extraversion,
      agreeableness, neuroticism}` on a **1-7** scale
    - `scale`, `n_seconds`, `confidence`, `notes`,
      `model_version`, `disclaimer`

Costs 10 credits.
```

#### `analyze_deception_pair()`

Which of two clips of the SAME speaker departs more toward deception (`POST /v1/analyses/deception-pair`).

Within-speaker comparison — the person is their own baseline. 68% paired
accuracy in validation (chance 50%, trained humans ~54%). Both clips must
be the same speaker for the result to mean anything.

**Args**

```text
    audio_id_a: `audioId` of the first clip.
    audio_id_b: `audioId` of the second clip (must differ from A).
```

**Returns**

```text
    `Job`; after `wait()`, `.result` has:

    - `more_likely_deceptive`: `"A"` or `"B"`
    - `score_a`, `score_b` (0-1); `margin` = |score_a - score_b|
      (small margins ≈ a coin flip — report them as such)
    - `n_seconds_a`, `n_seconds_b`, `notes`, `model_version`,
      `disclaimer`
```

#### `analyze_convergence()`

Phonetic-convergence (familiarity) signal between two DIFFERENT speakers (`POST /v1/analyses/convergence`).

Research-stage, category-of-one capability: the vocal signature of prior
interaction. A lead for investigators, not proof of contact.

**Args**

```text
    audio_id_a: `audioId` of the first clip.
    audio_id_b: `audioId` of the second clip (must differ from A).
```

**Returns**

```text
    `Job`; after `wait()`, `.result` has:

    - `familiarity_signal` (float): higher = more convergence
    - `n_seconds_a`, `n_seconds_b`, `notes`, `model_version`,
      `disclaimer`
```

#### `analyze_file()`

Upload a single-speaker clip, run audio lines, wait, return results — one call.

Convenience over `upload_audio()` + `analyze_*` + `wait()`. For
MULTI-speaker recordings use `analyze_session()` instead.

**Args**

```text
    path: Local audio file (one speaker).
    lines: Analyses to run — any of `"deception"`, `"voice-personality"`.
        Default runs both.
    content_type: MIME type (see `upload_audio()`).
    timeout: Max seconds to wait per line.
    delete_after: Delete the uploaded audio when done (recommended for
        sensitive material).
```

**Returns**

```text
    dict `{"audio_id": ..., "<line>": result_dict, ...}`; each result
    follows the matching `analyze_*` schema; a failed line yields
    `{"error": "<status>"}`.
```

**Raises**

```text
    ValueError: unknown line name.
    TimeoutError: a line did not finish within `timeout`.
```

#### `audio_status()`

Current status of an uploaded audio file (`GET /v1/audio/{id}`).

**Args**

```text
    audio_id: `audioId` from `upload_audio()`.
```

**Returns**

```text
    dict: `audioId`, `filename`, `status` (`pending` / `uploaded`
    / `deleted`), `contentType`, `createdAt`.
```

#### `delete_audio()`

Delete an uploaded audio file from storage immediately (idempotent).

Removes the stored audio and marks the record `deleted`. Analysis
*results* already produced from it are retained (scores, not audio). All
audio auto-deletes after 7 days regardless.

**Args**

```text
    audio_id: `audioId` from `upload_audio()`.
```

**Returns**

```text
    dict: `audioId`, `filename`, `status="deleted"`.
```

<a id="sessions"></a>

## Sessions (multi-speaker recordings)

ONE recording, SEVERAL speakers: diarization + transcription + per-speaker behavioral scores + time series. PHI mode for clinical work.

_All scores are research signals intended to inform professional judgment — not diagnoses, accusations, lie detection, or determinations of fact._

#### `analyze_session()`

Analyze ONE multi-speaker recording end-to-end (`POST /v1/analyses/session`).

For interviews, clinical/therapy sessions, meetings, depositions.
Pipeline: speaker diarization + transcription (AssemblyAI; under a BAA,
PHI mode available) → per-speaker communication style and Big Five via
the production text models → per-speaker behavioral time series →
optional per-speaker vocal deception on speaker-isolated audio. No LLM is
involved at any step.

**Args**

```text
    path: Local recording with several speakers.
    mime_type: MIME type (`"audio/wav"`, `"audio/mpeg"`, `"audio/mp4"`,
        `"audio/flac"`, `"audio/ogg"`).
    lines: Outputs to produce — any subset of `"transcript"`,
        `"speakers"`, `"style"`, `"personality"`, `"segments"`,
        `"deception"`. Default: all except `"deception"`.
    include_deception: Shortcut that adds `"deception"` to `lines`. Off
        by default; in clinical settings consider leaving it off.
    phi: PHI mode — redacts PII/PHI in the transcript (person names, phone,
        email, location, date of birth, SSN, medical condition, drug,
        injury, blood type, medical procedure, healthcare numbers, card
        numbers) and deletes the transcript from the transcription vendor
        after retrieval. Use within a BAA-covered workspace.
    redact_policies: Override the redaction policy list (AssemblyAI policy
        names, e.g. `"person_name"`, `"medical_condition"`, `"drug"`,
        `"location"`, `"date_of_birth"`). Implies redaction even when
        `phi` is False.
    language_code: ISO code for transcription (default `"en"`).
    delete_after: Delete the uploaded audio when done.
    timeout: Max seconds to wait for the job (default 3600).
    poll_s: Seconds between status polls.
    on_status: Optional callback `fn(status, stage)` called on each poll
        with `"queued"` / `"processing"` / `"completed"` / `"failed"`.
```

**Returns**

```text
    `SessionResult`:

    - `status` (`"completed"`, `"failed: ..."` or `"timeout ..."`),
      `job_id`, `upload_id` (the audioId)
    - `transcript`: utterances `{speaker, start_ms, end_ms, text,
      n_words}`; speakers are labelled `"A"`, `"B"`, ...
    - `behavioral_speakers`: per speaker `{speaker, n_utterances,
      n_words, speaking_time_s, style{dimensions...},
      personality{traits...}}` — style/personality omitted (with a
      `note`) for speakers under 50 words
    - `behavioral_segments`: per-speaker sliding windows of 6 utterances
      `{speaker, start_ms, end_ms, n_words, style{dim: z}}` — the
      behavioral time series
    - `deception_statements` (only if requested): per speaker
      `{speaker, audio_seconds, deception_score, model_version}`
    - `statistics`: `{n_speakers, n_utterances, duration_s,
      processing_s, transcription{provider, redacted, phi_mode},
      model_version}`
    - `raw`: the full result dict
    - `.speaker_frame()` / `.segment_frame()` → pandas DataFrames

Costs 40 credits per session (covers vendor transcription).
```

**Raises**

```text
    ArcheAPIError: `BAD_REQUEST` (bad line / audio not uploaded),
        `INSUFFICIENT_CREDITS`, trial codes.
```

<a id="jobs"></a>

## Jobs, account, models

Polling, credits, model catalog.

_All scores are research signals intended to inform professional judgment — not diagnoses, accusations, lie detection, or determinations of fact._

#### `job()`

Fetch the current state of an analysis job (`GET /v1/jobs/{id}`).

**Args**

```text
    job: a `Job` or job-id string.
```

**Returns**

```text
    `Job` with `status` in `queued` / `processing` /
    `completed` / `failed`, `result` populated when completed.
```

#### `wait()`

Poll a job until it completes or fails.

**Args**

```text
    job: a `Job` or job-id string.
    timeout: Max seconds to wait (text jobs finish in seconds, audio in
        ~10-60 s, sessions in 20 s to several minutes).
    interval: Seconds between polls.
```

**Returns**

```text
    The final `Job` (`completed` or `failed`; inspect
    `.result`).
```

**Raises**

```text
    TimeoutError: still running after `timeout` seconds.
```

#### `account()`

Account status for this API key: credits and (if any) trial terms.

**Returns**

```text
    dict: `userId`, `apiKeyId`, `keyPrefix`, `credits` (remaining
    workspace balance), `createdAt`, `lastUsedAt`, and — trial
    workspaces only — `trial` = `{label, allowedTickers, historyFrom,
    historyMonths, maxHistoryCallsPerDay, expiresAt, expired}`.
```

#### `models()`

List the models this key can invoke and what each costs.

**Returns**

```text
    DataFrame / list of dicts, one row per model: `modelSlug`, `name`,
    `description`, `creditsCost`, `isActive`, access info.
```

#### `model()`

Details for one model by slug (`GET /v1/models/{slug}`).

**Args**

```text
    slug: `modelSlug` as listed by `models()` (e.g.
        `"fraud-language-v1"`, `"behavioral-history-v1"`).
```

**Returns**

```text
    dict: `modelSlug`, `name`, `description`, `creditsCost`,
    `isActive`, `keyHasPermission` (whether this key may invoke it —
    tier-3 key grant only; workspace grants and default access are
    reflected in `models()`).
```

**Raises**

```text
    ArcheAPIError: `NOT_FOUND` for an unknown slug.
```

<a id="interpreting-scores"></a>

## Interpreting scores

Every ArcheAI output is a **research signal**: a measurement of how speech
reads against a validated reference, meant to inform professional judgment.
None is a diagnosis, an accusation, a lie detector, or a determination of
fact. This page explains what each number means and how far to trust it.

### Communication style (7 dimensions) — z-scores

Each dimension is a **z-score against executive-register norms** computed
on the research corpus. 0 = typical executive; +1 = one standard deviation
toward the *second* pole in the dimension's name; −1 = toward the first.

| dimension | first pole ← → second pole |
|---|---|
| `intellectual_colloquial` | intellectual ← → colloquial |
| `concrete_abstract` | concrete ← → abstract |
| `tentative_assertive` | tentative ← → assertive |
| `authority_people` | authority-oriented ← → people-oriented |
| `formal_conversational` | formal ← → conversational |
| `uncertain_certain` | uncertain ← → certain |
| `pessimistic_optimistic` | pessimistic ← → optimistic |

Rules of thumb: |z| < 0.5 is unremarkable; |z| > 1 is a notable departure;
|z| > 2 is rare (~2% of executive speech). The norms are executive speech —
other registers (casual conversation, clinical sessions) will sit off-centre
*as a population*; compare within your own sample or to a speaker's own
history rather than to 0 in those settings. `component_coverage` < 0.5
means the text had few of the dimension's lexical markers; treat the score
as low-confidence.

**The most informative use is change over time.** A speaker's deviation
from *their own* baseline (what `behavioral_history()` gives you for
executives, and what session `segments` give you within a recording) is
the patented ArcheAI construct and carries more signal than any absolute
level.

### Big Five (text and voice) — 1 to 7

`openness`, `conscientiousness`, `extraversion`, `agreeableness`,
`neuroticism` on a 1–7 scale (4 = midpoint). The **text** model is
reference-grade (r .92–.96 vs a psychologist panel on held-out speakers).
The **voice-only** model is verification-grade (r .33–.41) — use it to
corroborate the text estimate, not alone. Text `confidence` tiers
(`low` < 200 words → `high` ≥ 2000) tell you how settled the estimate is.
These measure *expressed* personality in a context; they are not clinical
instruments.

### Fraud-language score — 0 to 1

Probability-like output of a mixture-of-experts model trained on executive
Q&A speech from SEC-enforcement eras (AUC 0.874, frozen holdout). Higher =
more similar to enforcement-era speech patterns. It flags *speech that
reads like* historically problematic speech; it says nothing about the
truth of any statement. `experts.deviation` is `None` for one-shot text —
the strongest expert needs a speaker's history, which only the research
corpus provides.

### Vocal deception indicators — 0 to 1

Acoustic-feature model validated on incentivized revealed-truth corpora.
Three cautions: (1) it measures *vocal patterns associated with* deception
under those conditions, not lying; (2) ≥10 s of one speaker's speech is
needed; (3) the **within-speaker pair** version (`analyze_deception_pair`,
68% paired accuracy) is far more valid than a single absolute score,
because the speaker is their own baseline. Report small `margin` values as
coin flips.

What deception signals can and can't detect: they track a speaker's
relationship to their *own* statement in the moment. Chronic, normalized
behavior the speaker doesn't experience as lying produces no departure
from baseline — so an unflagged denial and a true accusation can coexist.

### Convergence / familiarity — unbounded float

Phonetic-convergence signal between two speakers (wav2vec2
representations). Higher = more convergence, consistent with prior
interaction. Research-stage; a lead, not evidence.

### Sessions

Per-speaker scores use the text models above on each speaker's
transcribed speech (minimum 50 words/speaker). `segments` are sliding
windows of 6 utterances → a style time series; look for *within-session
drift* rather than absolute levels. Diarization labels (`A`, `B`, …) are
positional, not identities.

<a id="errors"></a>

## Errors

All API errors raise `arche_ai.ArcheAPIError` with:

| attribute | meaning |
|---|---|
| `.status` | HTTP status code |
| `.code` | machine-readable code (below) |
| `.message` | human-readable explanation |
| `.meta` | dict of extra detail (e.g. `required`/`available` credits, `expiresAt`) |
| `.is_trial_limit` | `True` for the three `TRIAL_*` codes |

```python
from arche_ai import ArcheAPIError
try:
    df = c.behavioral_history("MSFT")
except ArcheAPIError as e:
    if e.is_trial_limit:
        ...  # outside the agreed trial scope — not a permissions problem
    elif e.code == "INSUFFICIENT_CREDITS":
        print(e.meta)  # {"required": 5, "available": 2}
    else:
        raise
```

| code | HTTP | when | what to do |
|---|---|---|---|
| `UNAUTHORIZED` | 401 | missing/invalid/revoked key | check the key; keys are workspace-scoped |
| `FORBIDDEN` | 403 | key lacks permission for this model | request access (model tiers are admin-granted) |
| `TRIAL_TICKER_DENIED` | 403 | ticker not on the trial's allow-list | request the ticker be added, or stay in scope |
| `TRIAL_DAILY_CAP` | 403 | daily `behavioral_history` cap reached | resets 00:00 UTC |
| `TRIAL_EXPIRED` | 403 | trial expiry passed — blocks **every** endpoint | contact ArcheAI to extend/convert |
| `INSUFFICIENT_CREDITS` | 402 | workspace balance below the model's cost | `meta.required` / `meta.available`; top up in the web app |
| `BAD_REQUEST` | 400 | invalid body (text too short, bad `lines`, audio not confirmed) | `meta.fieldErrors` when present |
| `NOT_FOUND` | 404 | unknown ticker / audio id / job id / inactive model | — |
| `INTERNAL_SERVER_ERROR` | 500 | server fault | retry; report with the job id if persistent |

Job-level failures (the job was accepted but processing failed) do **not**
raise — `wait()` returns a `Job` with `status="failed"`; the gateway's
`error` field is available via `client.job(job_id)`. Credits for failed
jobs are reviewed and refunded by support.

`TimeoutError` (standard library) is raised by `wait()` / `analyze_file()`
when a job is still running after `timeout` seconds — the job itself
continues; poll again with `client.job(job_id)`.
