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 |
last_headers |
dict[str, str]
|
Headers of the most recent response. |
last_url |
str | None
|
URL of the most recent response, or |
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
|
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 |
Raises:
| Type | Description |
|---|---|
KawaError
|
If the API returns a non-2xx response. |
KawaValidationError
|
If the response doesn't match |
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 |
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 |
None
|
transcript_text
|
str | None
|
A transcript supplied directly,
with no transcription job behind it. Mutually exclusive
with |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Job |
Job
|
The newly created job ( |
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 |
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 |
None
|
transcript_text
|
str | None
|
A transcript supplied directly,
with no transcription job behind it. Mutually exclusive
with |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Job |
Job
|
The newly created job ( |
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 |
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 |
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 ( |
Raises:
| Type | Description |
|---|---|
TimeoutError
|
If |
KawaError
|
If the API returns a non-2xx response. |
KawaValidationError
|
If a response doesn't match |
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 |
type |
str | None
|
|
status |
str
|
Current lifecycle status, e.g. |
source_job_id |
str | None
|
The transcription this job was derived
from, for a |
result |
TranscriptResult | SummaryResult | TagsResult | None
|
The
job's result, once |
error |
JobError | None
|
The failure detail, once |
received_at |
str | None
|
Submission timestamp, only on
|
original_filename |
str | None
|
Only on |
language |
str | None
|
Requested/submission-time language code, only
on |
audio_seconds |
float | None
|
Only on |
created_at |
str | None
|
Only on |
updated_at |
str | None
|
Only on |
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, |
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.
|
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. |
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 |
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 |
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
|
required |
headers
|
dict[str, str] | None
|
The response headers, if any. |
None
|