Skip to content

Python SDK API Reference

Client

makimoto.kawa.KawaClient

Minimal client for the Makimoto Kawa transcription API.

Credentials: pass api_key explicitly, or omit it and set the MAKIMOTO_API_KEY environment variable instead, the explicit argument always wins if both are present. Neither being set doesn't raise here, only lazily, the first time a method actually sends a request. This is a static API key (create one from the dashboard), not the short-lived dashboard login JWT, the transcription endpoints this client calls no longer accept that.

Transport: uses httpx2.Client internally, one instance per KawaClient, reused across calls, with follow_redirects=True set explicitly (not the library default, kept to match this client's previous requests-based behaviour).

Attributes:

Name Type Description
api_key str

API key, stripped of surrounding whitespace.

api_url str

Base URL for the API, trailing slash removed.

timeout float

Default per-request timeout, in seconds.

last_status int | None

HTTP status code of the most recent response, or None before any request has been made.

last_headers dict[str, str]

Headers of the most recent response.

last_url str | None

URL of the most recent response, or None before any request has been made.

Examples:

>>> client = KawaClient(api_key="<your api key>")
>>> job = client.transcribe("call.mp3", language="en")
>>> print(job.result.full_text)

__init__(api_key=None, api_url=DEFAULT_API_URL, *, timeout=30.0, session=None)

Initialise the client.

Parameters:

Name Type Description Default
api_key str | None

API key. If omitted, falls back to the environment variable.

None
api_url str

Base URL for the API.

DEFAULT_API_URL
timeout float

Default per-request timeout, in seconds.

30.0
session Client | None

Existing HTTP client to reuse. If omitted, a new one is created with follow_redirects=True.

None

close()

Close the underlying HTTP session, releasing pooled connections.

KawaClient holds one persistent httpx2.Client for its whole lifetime. Closing it doesn't matter for a short script, the process exit cleans it up either way, but does matter for a long-running app that keeps a client around, a server, a worker, and so on.

list_jobs(*, limit=None, cursor=None, status=None, job_type=None, language=None, created_after=None, job_id=None)

GET /v1/transcriptions - one page of jobs for the authenticated account.

Keyset-paginated: limit defaults to 10 server-side and is capped at 100; pass cursor=page.next_cursor to fetch the next page, next_cursor is None once there's nothing left. status, job_type ("transcription", "summary", or "tags"), language, created_after (an ISO 8601 timestamp), and job_id (a UUID) are optional filters, composed with AND where more than one is given. With no job_type, every job type is returned, the API applies no implicit filter of its own.

Every argument is passed straight through as a query parameter ( job_type as type), an invalid value (e.g. an unrecognised status) raises KawaError from the backend rather than being validated here, that keeps this client from carrying its own copy of rules the API already owns.

iter_jobs(*, page_size=None, status=None, job_type=None, language=None, created_after=None, job_id=None)

Yield every matching job, fetching further pages automatically.

A thin wrapper around list_jobs() for the common case of wanting all matching jobs rather than one page at a time. page_size controls the underlying per-request limit (server default 10, capped at 100), not how many jobs this yields overall, use list_jobs directly if you need explicit control over paging instead.

create_transcription(file_path, *, language=None, metadata=None)

POST /v1/transcriptions - submit a recording as multipart form-data.

Parameters:

Name Type Description Default
file_path str | Path

Path to the audio/video file to upload.

required
language str | None

Optional language hint for transcription.

None
metadata dict[str, Any] | None

Optional metadata to attach to the job, sent as a JSON string.

None

Returns:

Name Type Description
Job Job

The newly created job (typically queued or processing).

Raises:

Type Description
KawaError

If the API returns a non-2xx response.

KawaValidationError

If the response doesn't match Job's shape.

get_job(job_id)

GET /v1/transcriptions/{job_id} - status, and result once done.

Parameters:

Name Type Description Default
job_id str

The job's identifier.

required

Returns:

Name Type Description
Job Job

The job's current state.

Raises:

Type Description
KawaError

If the API returns a non-2xx response.

KawaValidationError

If the response doesn't match Job's shape.

delete_job(job_id)

DELETE /v1/transcriptions/{job_id} - remove a job, where supported.

Works for any job type (transcription, summary, or tags).

Deleting a transcription does not delete summaries or tags derived from it; delete those separately by their own job_id.

Parameters:

Name Type Description Default
job_id str

The job's identifier.

required

Returns:

Type Description
dict[str, Any]

dict[str, Any]: The API's response body.

Raises:

Type Description
KawaError

If the API returns a non-2xx response.

create_summary(transcription_job_id=None, *, transcript_text=None)

POST /v1/summarize - create a summary job from a transcript.

Exactly one of transcription_job_id or transcript_text must be given, the API rejects zero or both with a 400.

Parameters:

Name Type Description Default
transcription_job_id str | None

One of the caller's own transcription jobs, in status succeeded. Mutually exclusive with transcript_text.

None
transcript_text str | None

A transcript supplied directly, with no transcription job behind it. Mutually exclusive with transcription_job_id.

None

Returns:

Name Type Description
Job Job

The newly created job (type="summary", typically processing).

Raises:

Type Description
KawaError

If the API returns a non-2xx response, including a 400 when neither or both of the two arguments are given.

KawaValidationError

If the response doesn't match Job's shape.

create_tags(transcription_job_id=None, *, transcript_text=None)

POST /v1/tag - create a tags job from a transcript.

Exactly one of transcription_job_id or transcript_text must be given, the API rejects zero or both with a 400.

Note that the tag taxonomy is fixed by the service and isn't configurable per account.

Parameters:

Name Type Description Default
transcription_job_id str | None

One of the caller's own transcription jobs, in status succeeded. Mutually exclusive with transcript_text.

None
transcript_text str | None

A transcript supplied directly, with no transcription job behind it. Mutually exclusive with transcription_job_id.

None

Returns:

Name Type Description
Job Job

The newly created job (type="tags", typically processing).

Raises:

Type Description
KawaError

If the API returns a non-2xx response, including a 400 when neither or both of the two arguments are given.

KawaValidationError

If the response doesn't match Job's shape.

poll(job_id, *, interval=2.0, max_attempts=60)

Yield the job on each poll until it reaches a terminal status.

Poll GET /v1/transcriptions/{job_id} every interval seconds while the status is queued or processing; stop on succeeded or failed. Yielding (rather than blocking) lets a UI show live updates. Gives up silently after max_attempts, use transcribe() instead if you want a clear exception on timeout.

Parameters:

Name Type Description Default
job_id str

The job's identifier.

required
interval float

Seconds to sleep between polls.

2.0
max_attempts int

Maximum number of polls before giving up.

60

Yields:

Name Type Description
Job Job

The job's state on each poll.

Raises:

Type Description
KawaError

If the API returns a non-2xx response.

KawaValidationError

If a response doesn't match Job's shape.

transcribe(file_path, *, language=None, metadata=None, interval=2.0, max_attempts=60)

Submit and poll in one call. Raises on timeout, not on a failed job.

A failed job is a normal outcome (bad audio, unsupported language), not a malfunction, returned like get_job() would, check .status/.error. Only exhausting max_attempts without reaching a terminal status raises, since that's genuinely exceptional.

Parameters:

Name Type Description Default
file_path str | Path

Path to the audio/video file to upload.

required
language str | None

Optional language hint for transcription.

None
metadata dict[str, Any] | None

Optional metadata to attach to the job.

None
interval float

Seconds to sleep between polls.

2.0
max_attempts int

Maximum number of polls before giving up.

60

Returns:

Name Type Description
Job Job

The job in its terminal state (succeeded or failed).

Raises:

Type Description
TimeoutError

If max_attempts is exhausted before the job reaches a terminal status.

KawaError

If the API returns a non-2xx response.

KawaValidationError

If a response doesn't match Job's shape.

Models

makimoto.kawa.Job

Bases: BaseModel

A job, in whatever state the API last reported.

Covers all three job types the API produces: a transcription itself, plus a summary or tags job created from one via KawaClient.create_summary() / KawaClient.create_tags(). type says which, and therefore which shape result takes; result is only present once succeeded, error only once failed.

The fields below aren't all present on every response; each is only sent by specific endpoints: - received_at only on the response to create_transcription(); - original_filename, language, audio_seconds, created_at and updated_at only on list_jobs()/iter_jobs() entries.

type is present on both get_job() and list_jobs()/ iter_jobs() entries, always "transcription", "summary" or "tags".

language here is the list view's own top-level field (whatever was requested at submission), distinct from the detected language on result.language, which only exists once a job succeeds.

Attributes:

Name Type Description
job_id str

The job's identifier. Poll a summary or tags job by its own job_id, not the source transcription's.

type str | None

"transcription", "summary", or "tags". None on a response that predates this field, treated the same as "transcription" for parsing result.

status str

Current lifecycle status, e.g. "queued", "processing", "succeeded", or "failed".

source_job_id str | None

The transcription this job was derived from, for a summary or tags job. None for a transcription itself, which has no source.

result TranscriptResult | SummaryResult | TagsResult | None

The job's result, once succeeded; its shape follows type.

error JobError | None

The failure detail, once failed.

received_at str | None

Submission timestamp, only on KawaClient.create_transcription()'s response.

original_filename str | None

Only on list_jobs()/ iter_jobs() entries.

language str | None

Requested/submission-time language code, only on list_jobs()/iter_jobs() entries; distinct from the detected result.language.

audio_seconds float | None

Only on list_jobs()/ iter_jobs() entries.

created_at str | None

Only on list_jobs()/ iter_jobs() entries.

updated_at str | None

Only on list_jobs()/ iter_jobs() entries.

is_terminal property

True once status is "succeeded" or "failed".

Returns:

Name Type Description
bool bool

Whether the job has reached a terminal status.

makimoto.kawa.TranscriptResult

Bases: BaseModel

The result payload returned once a job succeeds. Frozen.

segments reads from the API's transcript key, the Python-facing name stays segments for readability; the wire format doesn't have to match the attribute name.

Attributes:

Name Type Description
language str | None

Detected or requested language code.

duration_seconds float | None

Duration of the recording, in seconds.

words_count int | None

Total number of transcribed words.

segments list[Segment]

Speaker-attributed slices of the transcript.

full_text property

Every segment's text, joined with a space.

Returns:

Name Type Description
str str

The full transcript text.

makimoto.kawa.SummaryResult

Bases: BaseModel

The result payload for a summary job. Frozen.

Attributes:

Name Type Description
topic str | None

Short label for what the call was about, None if the model produced none.

summary str

Prose summary of the conversation.

meta_data dict[str, Any] | None

Generation metadata reported by the provider (model, batch size, timing), passed through unread.

makimoto.kawa.TagsResult

Bases: BaseModel

The result payload for a tags job. Frozen.

The tag taxonomy is fixed by the service and isn't configurable per account.

Attributes:

Name Type Description
tags dict[str, list[str]]

Tag category to selected values, e.g. {"call_reason": ["billing_issue"]}.

meta_data dict[str, Any] | None

Generation metadata reported by the provider, passed through unread.

makimoto.kawa.Segment

Bases: BaseModel

One speaker-attributed slice of the transcript. Frozen.

If the API omits speaker_alias, a speaker_id-based default is filled in before validation ("Speaker 0", etc.)

Attributes:

Name Type Description
text str

The segment's transcribed text.

time_start float

Start time of the segment, in seconds.

time_end float

End time of the segment, in seconds.

speaker_id int

Numeric identifier of the speaker.

speaker_alias str

Human-readable speaker label, e.g. "Speaker 0".

makimoto.kawa.TranscriptionPage

Bases: BaseModel

One page of KawaClient.list_jobs(). Frozen.

next_cursor is None once there's nothing left; pass it back as list_jobs(cursor=page.next_cursor) to fetch the next page.

makimoto.kawa.JobError

Bases: BaseModel

The error payload returned once a job fails.

Attributes:

Name Type Description
code str

Machine-readable error code.

message str

Human-readable error message.

provider_error dict[str, Any] | None

Raw error detail from the underlying transcription provider, if any.

Exceptions

makimoto.kawa.KawaError

Bases: RuntimeError

Raised when the API returns a non-2xx response.

status_code, body and headers are kept so callers can branch on, for example, a 401 (API key missing/invalid) versus a 404 (unknown job), and inspect response headers (such as Retry-After on a 429, or the Server header that reveals whether a 413 came from the API or a proxy in front of it).

Attributes:

Name Type Description
status_code int

The response's HTTP status code.

body Any

The parsed response body (or {"raw": ...} if it wasn't valid JSON).

url str

The request URL that produced this response.

headers dict[str, str]

The response headers.

__init__(status_code, body, url, headers=None)

Initialise the error.

Parameters:

Name Type Description Default
status_code int

The response's HTTP status code.

required
body Any

The parsed response body.

required
url str

The request URL that produced this response.

required
headers dict[str, str] | None

The response headers, if any.

None

makimoto.kawa.KawaValidationError

Bases: KawaError

Raised when a successful response doesn't match the expected shape.

A subclass of KawaError, so except KawaError catches this too.

Attributes:

Name Type Description
validation_error Exception

The underlying pydantic.ValidationError.

status_code int

The response's HTTP status code.

body Any

The parsed response body.

url str

The request URL that produced this response.

headers dict[str, str]

The response headers.

__init__(status_code, body, url, validation_error, headers=None)

Initialise the error.

Parameters:

Name Type Description Default
status_code int

The response's HTTP status code.

required
body Any

The parsed response body that failed validation.

required
url str

The request URL that produced this response.

required
validation_error Exception

The underlying pydantic.ValidationError this wraps.

required
headers dict[str, str] | None

The response headers, if any.

None