Skip to main content

Nexara Python SDK

Python SDK for the Nexara speech-to-text API: transcription, speaker diarization, speaker role tagging, structured LLM post-processing, realtime streaming over WebSocket, and account billing. Full API documentation lives at docs.nexara.ru.

Requires Python 3.10+.

pip install nexara

Quickstart

from nexara import Nexara

client = Nexara(api_key="...")  # or set NEXARA_API_KEY

text = client.transcriptions.create(file="audio.mp3").text

Pass exactly one of file= (path, bytes, or a binary file object — paths are streamed from disk, not loaded into memory) or url=.

Diarization

call = client.transcriptions.create(file="call.mp3", task="diarize")
for segment in call.segments:
    print(f"{segment.speaker}: {segment.text}")

Add meaningful speaker labels with roles — "auto" lets the model invent labels, a list restricts them, a dict adds descriptions:

call = client.transcriptions.create(
    file="call.mp3",
    task="diarize",
    roles=["client", "agent"],
)

Emotions

emotions=True attaches an emotion to each diarized segment — label (one of angry, sad, neutral, positive), confidence, and the full probs distribution when the server sends it:

call = client.transcriptions.create(
    file="call.mp3",
    task="diarize",
    model="nexara-ru",
    emotions=True,
)
for segment in call.segments:
    if segment.emotion:
        print(segment.speaker, segment.emotion.label, segment.emotion.confidence)

The scoring runs inside the ASR model, so it requires task="diarize", model="nexara-ru" and a JSON response format; anything else raises NexaraValidationError before the upload. Not every segment can be scored, so check segment.emotion rather than assuming it is there. It carries a per-second surcharge, charged only when emotion was actually returned.

Long audio: deferred jobs

create_job() submits the audio and returns immediately; the result is fetched by polling. A failed job is never billed, so resubmitting is free.

job = client.transcriptions.create_job(file="long_recording.mp3")
result = job.wait()  # polls; default timeout 1800s

# ...or pick it up later, even from another process:
job = client.transcriptions.retrieve_job(job_id)

Job results live for 12 hours from creation; up to 200 jobs may be in progress per API key. In this SDK "async" always means asyncio — the deferred mode is create_job(), not AsyncNexara.

LLM post-processing

Pass prompt= to run an LLM over the transcript, and optionally json_schema= to force structured output:

result = client.transcriptions.create(
    file="meeting.mp3",
    prompt="Summarize the key decisions",
    json_schema={"type": "object", "properties": {"decisions": {"type": "array"}}},
)
print(result.llm_output)          # dict, validated against your schema
print(result.transcription.text)  # the transcript it was derived from

Realtime streaming

Stream raw audio in, get words back as they are recognised. Every word the server sends is final — there are no interim results, so append event.text and never look back. Requires the websockets extra: pip install nexara[realtime].

import asyncio
from nexara import AsyncNexara

async def main():
    client = AsyncNexara()
    async with client.realtime.connect(sample_rate=16000, diarize=True) as session:
        async for event in session.stream(microphone()):   # any async iterator of PCM bytes
            print(f"spk{event.speaker} {event.words[0].start / 1000:6.2f}s {event.text}")
        print(session.ended.text)                          # full transcript + billing summary

asyncio.run(main())

Audio is raw PCM — int16 little-endian, 16 kHz mono by default — in binary frames of roughly 20 ms to 1 s. connect() takes the session parameters: encoding (pcm_s16le, pcm_f32le, pcm_mulaw, pcm_alaw), sample_rate (8–48 kHz, resampled server-side), channels, multichannel (transcribe stereo channels separately), diarize, delay_ms (emission delay: longer is more accurate, shorter is faster; default 480) and client_id. Language is auto-detected.

stream() pumps an iterator in and yields RealtimeTranscript events out. When sending from your own task, use send_audio() and then finish(), which sends end-of-audio and returns the session.ended summary once the server has flushed the model's delay line:

async with client.realtime.connect() as session:
    async def send():
        async for chunk in microphone():
            await session.send_audio(chunk)
        await session.finish()

    asyncio.create_task(send())
    async for event in session:
        print(event.text, end="", flush=True)

Word timestamps are integer milliseconds on the audio clock (since the first sample you sent) at 80 ms resolution. With diarize=True, speaker is 0–3 by order of first appearance, or None when the diarizer could not tell. A session with no audio for 30 s is closed unless you call keepalive().

A session that the server ends raises from the iterator: RealtimeError with .code and .reason (session_full, idle_timeout, audio_backlog, service_restart, …), or InsufficientBalanceError if the wallet ran out mid-session. Everything the server had finalised is delivered before the error, so what you received is what you were billed for. A rejected handshake (bad key, no funds, too many sessions) raises the same status-mapped exceptions as the REST API.

Balance and usage

client.billing reports what is on the account and what it has been spent on. Both endpoints cover the whole account, not just the key you authenticate with:

balance = client.billing.balance()
print(balance.balance, balance.currency, balance.rate_per_min)

# One page of billed calls, newest first.
page = client.billing.usage(limit=20)
for item in page.items:
    print(item.timestamp, item.task, item.cost, item.api_key.name)

# ...or let the SDK walk the pages. History is unbounded — bound it.
for item in client.billing.iter_usage(max_items=200):
    print(item.request_id, item.seconds, item.cost)

Paging is keyset-based, not offset-based: pass a page's next_cursor as cursor= to get the next (older) page, so calls arriving mid-walk cannot shift rows across a page boundary. item.cost is None — not 0 — for rows written before per-request costs were recorded, and rate_per_min covers plain transcription only (profanity_filter, roles, emotions and prompt are surcharges on top of it).

asyncio

AsyncNexara is the same interface under await:

from nexara import AsyncNexara

async with AsyncNexara() as client:
    result = await client.transcriptions.create(file="audio.mp3")
    print(result.text)

Errors and validation

Requests that the server would reject — or, worse, accept, charge for, and silently do something else with — fail client-side with NexaraValidationError before any network call. Server errors map to typed exceptions by status code:

from nexara import NexaraValidationError, InsufficientBalanceError, RateLimitError

try:
    result = client.transcriptions.create(file="audio.mp3")
except InsufficientBalanceError as e:  # 402
    print(e.detail)

429 and connection/timeout failures are retried with exponential backoff (honoring Retry-After). 500 is deliberately not retried: on the synchronous path the request may already have been billed, so a blind retry could pay twice. Deferred jobs bill only on success, which makes create_job() the safe path for retry-heavy workloads.

Not yet available

  • Webhooks — job results are fetched by polling.

Development

The package is fully typed (py.typed, mypy strict). Offline tests (pytest, no network needed) and runnable examples live in the repository; NEXARA_USE_MOCK=1 runs everything against an in-memory mock transport.

License

MIT

Metadata

Release files for nexara 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nexara 0.6.0
File Size Uploaded Provenance
nexara-0.6.0.tar.gz 55.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nexara 0.6.0
File Interpreter ABI Platform
nexara-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 103.9 kB

Release files / nexara-0.6.0.tar.gz

Download URL nexara-0.6.0.tar.gz
Size 55.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4765af4fa5aa117d7ae9db22ae40e63659bf98c0149745d190c5493b387f6314
BLAKE2b-256 checksum
How to use checksums
82002b7766cbe9d3d037b5e7a1bb46a2a1199363d8a771e0eac9e45f174b2d3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Release files / nexara-0.6.0-py3-none-any.whl

Download URL nexara-0.6.0-py3-none-any.whl
Size 48.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
47a0ea439f53263ff4c0ce34a37bcfe9d6fae413b15042fe2742d9a7a7aab589
BLAKE2b-256 checksum
How to use checksums
476cd7708cfdee626196a93dedede620129809f05b24f05b079b2acbdcdd35b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Security for nexara 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for nexara-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page