allisall
The allisall SDK for Python: a typed client for the allisall API, covering
events, imports, clients, agents, value models, costs, analytics,
calculations, reports and the dashboard. It has a sync client, Allisall,
and an async client, AsyncAllisall. Requires Python 3.11 or later.
Install
pip install allisall
Create a client
The client reads your API key from AIA_API_KEY:
export AIA_API_KEY=aia_...
from allisall import Allisall
with Allisall() as client:
health = client.health.get()
print(health.status)
You can also pass the key yourself, as Allisall(api_key=...). Create one
client and reuse it; with closes its connections when you are done, and so
does client.close().
Ingest events
from datetime import UTC, datetime
from decimal import Decimal
from allisall import Allisall
with Allisall() as client:
summary = client.events.ingest(
[
{
"timestamp": datetime.now(UTC),
"agent_key": "support-bot",
"category": "model",
"event_type": "completion",
"model": "gpt-4o",
"tokens_in": 1200,
"tokens_out": 300,
"cost": Decimal("0.0042"),
}
]
)
print(summary.accepted, summary.duplicates, summary.rejected)
ingest takes any number of events and sends them in batches of at most 500
events and 4,000,000 bytes. It retries a failure worth retrying, and returns
one summary for the whole list. A rejected event is counted in
summary.rejected, its problems are listed in summary.errors, and the
others are still stored. When summary.errors_truncated is True, the list
omits some problems, and a rejected event may have no entry. Write cost as
a Decimal to keep it exact.
Set your own event_id for at-least-once delivery
The SDK gives each event without an event_id a new UUID, so a retried batch
is never counted twice. That does not catch the same event sent again in a
later call. If your events can be delivered to you more than once, for
example from a queue, set event_id yourself, such as to the message id. The
API then stores the event once, however often it arrives.
Call the API
The client groups its methods by resource: client.clients,
client.agents, client.value_models, client.cost, client.analytics,
client.calculations, client.reports, client.dashboard and more. Each
method's documentation names the API operation it calls and the scope your
key needs.
from allisall import Allisall
with Allisall() as client:
created = client.clients.create(
{"name": "Acme Logistics", "status": "active", "client_key": "acme"}
)
# An update is a merge patch: a key you leave out keeps its value, and
# None clears it.
updated = client.clients.update(created.id, {"renewal_date": "2026-12-31"})
print(updated.name, updated.renewal_date)
A request body is a plain dict, typed as a TypedDict your type checker
can check. A response is a frozen dataclass. Amounts of money are a
Decimal both ways, and instants and dates come back as the API's RFC 3339
strings.
Each create method, and imports.commit, sends an Idempotency-Key. The
SDK sends the same key again on a retry, so a retry never creates a second
one. The key it generates lasts for one call. To make a create safe across a
restart of your program as well, pass your own key, such as one stored with
the work it belongs to:
from allisall import Allisall
with Allisall() as client:
created = client.clients.create(
{"name": "Acme Logistics", "status": "active"},
idempotency_key="onboarding-acme-logistics",
)
print(created.id)
Lists
A list method returns a page. Iterate it with for to get every item of
every page; the SDK fetches each page as the loop reaches it:
from allisall import Allisall
with Allisall() as client:
for agent in client.agents.list():
print(agent.agent_key, agent.name)
To work a page at a time, use the page itself. It holds its items in data,
and has_next_page() and get_next_page() move through the rest:
from allisall import Allisall
with Allisall() as client:
page = client.agents.list(limit=50)
print(len(page.data), page.has_next_page())
Async
AsyncAllisall takes the same options and has the same methods, each one a
coroutine. A list method's result is walked with async for, or awaited for
its first page:
import asyncio
from allisall import AsyncAllisall
async def main() -> None:
async with AsyncAllisall() as client:
detail = await client.clients.get("CLIENT_ID")
print(detail.name)
async for agent in client.agents.list():
print(agent.agent_key, agent.name)
asyncio.run(main())
Errors
Every error from the API or the network is an AllisallError. An error
response from the API is an APIError, with the HTTP status, the API's
error code and the request_id to quote when you report a problem. Branch
on code:
from allisall import Allisall, APIError, ErrorCode
with Allisall() as client:
try:
client.clients.delete("CLIENT_ID")
except APIError as err:
if err.code != ErrorCode.CLIENT_HAS_EVENTS:
raise
# Events carry the client's key, so mark the client churned instead.
client.clients.update("CLIENT_ID", {"status": "churned"})
A code this version of the SDK does not list arrives as a plain str, so
compare with == rather than matching only the listed members.
An APIConnectionError means no response arrived, after any retries. A few
errors are not an AllisallError. An argument the SDK cannot send raises a
ValueError before anything is sent. An error raised by your
token_provider reaches you unchanged.
The SDK retries a failure worth retrying, twice by default. Set
max_retries on the client, or on one call, to change that. It honours the
API's Retry-After. It retries only a request that cannot take effect twice:
a GET, PUT or DELETE; ingest, whose event ids deduplicate; and a call
that carries an Idempotency-Key. A PATCH, an import preview, and setting
a value model's line items are never retried. Setting line items is guarded
by the model's version, which refuses a repeat of a write that already
landed.
Every method also takes timeout, max_retries and headers for that one
call.
Token providers and sessions
A token_provider is a function the client calls before every attempt, to
get the credential it sends. Pass one instead of api_key, never with it.
Use one to read your API key at run time, for example from a secret store, so that a rotated key is picked up without a restart:
from allisall import Allisall
def api_key_from_secret_store() -> str:
# Your secret store's way to read the current allisall API key.
raise NotImplementedError
with Allisall(token_provider=api_key_from_secret_store) as client:
print(client.health.get().status)
Or use one to send a signed-in user's session token instead of an API key. Because the client calls it before every attempt, a refreshed token is picked up:
from allisall import Allisall
def current_session_token() -> str:
# Your sign-in library's way to read the signed-in user's session token.
raise NotImplementedError
with Allisall(token_provider=current_session_token) as client:
for item in client.clients.list():
print(item.name)
AsyncAllisall also accepts a provider that is a coroutine function. Ingest
takes an API key only, whether passed as api_key or returned by a provider.
Documentation
License
Apache-2.0. See LICENSE and NOTICE.
Metadata
Release files for allisall 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| allisall-0.2.0.tar.gz | 114.3 kB | With provenance | Details for allisall-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| allisall-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for allisall-0.2.0-py3-none-any.whl |
Total release size: 194.6 kB
Release files / allisall-0.2.0.tar.gz
| Download URL | allisall-0.2.0.tar.gz |
|---|---|
| Size | 114.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
daa0c65758e1a8a395fbb2e130b811ed471471ae2dcc2e17884897c3def006ec
|
|
BLAKE2b-256 checksum How to use checksums |
b5913cb58aeace318357e08c4da7db1f24c80ef05835c9804542b64c37c44cfc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 2, 2026.
Transparency logRelease files / allisall-0.2.0-py3-none-any.whl
| Download URL | allisall-0.2.0-py3-none-any.whl |
|---|---|
| Size | 80.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06cde22faba3a6d538f1922f197ebcf28a02e05e9dfe47c1eb282079aa6e636b
|
|
BLAKE2b-256 checksum How to use checksums |
884a73557e08faea57c9f23e6f180b19b1f36e5ffc82e58b12adb2ac1bededa8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 2, 2026.
Transparency logSecurity for allisall 0.2.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.
Attestation for allisall-0.2.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 Nov 2, 2026.
Transparency logA 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.