Python SDK: API Reference

This reference covers keito 0.3.0 and later. Imports use keito; the distribution is also named keito. For every REST operation and exact fields, use OpenAPI. Dedicated SDK coverage is smaller than the REST surface.

Clients

from keito import Keito, AsyncKeito

client = Keito()  # KEITO_API_KEY and KEITO_ACCOUNT_ID from environment
# Explicit options:
client = Keito(
    api_key="YOUR_API_KEY",
    account_id="YOUR_COMPANY_ID",
    base_url="https://app.keito-test.com",
    timeout=60.0,
    max_retries=2,
)

The async client accepts the same configuration. Use with Keito() as client or async with AsyncKeito() as client to close connections. A base URL ending in /api/v2 is normalized; resource paths already include that prefix.

Time entries

Method Purpose
time_entries.create(...) Required project_id, task_id, spent_date; completed hours or running-timer input
time_entries.start_timer(...) Required project, task and spent date; sets the running state; optional replace_running
time_entries.stop_timer(id, ...) Stop a running timer; optional notes
time_entries.restart_timer(id, ...) Restart a stopped entry; optional replace_running
time_entries.update(id, ...) Change editable time fields
time_entries.delete(id, ...) Explicitly remove an eligible entry
time_entries.list(...) Lazy iterator; supports date, project, user, source and other supported package filters

See Time Entries for concrete calls. started_time and ended_time use HH:mm workspace time, not ISO timestamps. Only one timer can run for one user. Use source="api" for ordinary custom automation; lifecycle agent entries require Keito’s separate metadata contract.

Expenses

Method Purpose
expenses.create(...) Required project, category and spent date; total_cost or units according to category
expenses.get(id, ...) Read an expense
expenses.update(id, ...) Change editable expense fields
expenses.delete(id, ...) Explicitly delete an eligible expense
expenses.list(...) Lazy expense iterator
expenses.upload_receipt(id, file=..., filename=..., content_type=...) Upload bytes or a binary file object as multipart data
expenses.download_receipt(id, ...) Return receipt bytes
expenses.delete_receipt(id, ...) Remove the stored receipt

No top-level unit_price argument is accepted. The rate comes from the selected category. See Expenses for receipt limits and mutation examples.

Iteration and source filters

from keito.types.common import Source

for entry in client.time_entries.list(source=Source.API):
    print(entry.id, entry.hours)

# A valid string is also accepted:
for expense in client.expenses.list(source="api"):
    print(expense.id)

Sync list methods return SyncPageIterator; async lists return AsyncPageIterator. They are consumed with for and async for, respectively. Do not await the list call or use .data. Page metadata becomes available as pages are fetched. Pagination errors propagate instead of returning a silently partial successful list.

Request options and errors

from keito.core.request_options import RequestOptions
from keito import KeitoApiError, KeitoAuthError, KeitoRateLimitError

options = RequestOptions(
    additional_headers={"Idempotency-Key": "expense-operation-unique-001"},
    max_retries=0,
)

request_options is accepted by resource methods. Use a stable key only for the identical supported mutation; a changed request requires a new decision/key. Do not automatically retry a receipt stream. HTTP errors retain response details; KeitoAuthError, KeitoForbiddenError, KeitoNotFoundError, KeitoConflictError, KeitoRateLimitError, KeitoServerError and KeitoValidationError specialize KeitoApiError. KeitoTimeoutError and KeitoConnectionError are transport failures.

Models and optional fields

Response models are Pydantic models. spent_date is a date; timestamps are datetime. Financial fields may be absent or null according to authority and the endpoint. The expense’s configured rate belongs to expense_category.unit_price. User directory and /users/me projections differ; a model or a copied example does not expand API visibility.

There are no built-in framework callbacks, track_agent_work context manager or track decorator. Define a wrapper explicitly using Agent Integration.