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.