irusdk
A Python SDK and thin CLI for querying and acting on an Iru (formerly Kandji) fleet — devices, their state, the actions you take against them, and the blueprints, users, and tags that organise them.
Features
- Sync and async clients —
IruClientandAsyncIruClient, same surface, same models. - Pydantic models for API responses, so you get real attributes and IDE autocomplete.
- Transparent pagination — list methods iterate every page for you, with concurrent prefetch where the API exposes a total.
- Rate-limit aware — honors Iru's 50 req/sec and 10,000 req/hour tenant limits, with
Retry-Afterbackoff on 429. - Optional CLI for ad-hoc terminal use.
Installation
pip install irusdk # library only
pip install irusdk[cli] # library plus the `irusdk` command
Quickstart
from irusdk import IruClient
client = IruClient(subdomain="mycompany", token="...")
for device in client.devices.list(platform="Mac"):
print(device.device_name, device.serial_number, device.os_version)
No with block is required — construct the client and use it, the way you would httpx.Client.
Call client.close() when you are finished to release the connection pool promptly, or use the
client as a context manager and let it close itself:
with IruClient(subdomain="mycompany", token="...") as client:
device = client.devices.get("2cfeb3ac-3b5d-423e-bcff-e2676a3a32da")
The async client is the same code plus async:
import asyncio
from irusdk import AsyncIruClient
async def main():
client = AsyncIruClient(subdomain="mycompany", token="...")
async for device in client.devices.list(platform="Mac"):
print(device.device_name, device.serial_number)
await client.aclose()
asyncio.run(main())
What's covered
| Attribute | Endpoints |
|---|---|
client.devices |
list, pages, get, update, delete, details |
client.blueprints |
list, pages, get, create, update, delete, library items, templates |
client.users |
list, get, delete |
client.tags |
list, create, update, delete |
Pagination
List methods paginate for you — client.devices.list() walks every page and yields Device
models. When you want page boundaries, the reported total, or control over how many pages are in
flight, use pages() instead:
for page in client.devices.pages(platform="Mac", prefetch=8):
print(f"page {page.index}: {len(page)} devices of {page.total}")
CLI
export IRU_SUBDOMAIN=mycompany
export IRU_API_TOKEN=...
irusdk devices list --platform Mac
irusdk devices get <device-id>
irusdk blueprints list
irusdk users list --limit 50
irusdk tags create "lab-machines"
Every read command takes --json.
Scope
irusdk covers the Iru API: the fleet surface — devices, actions, Prism, users, tags,
blueprints — and, from 0.2.0, library-content authoring.
| Library item | Authoring support |
|---|---|
| Custom Scripts | available |
| Custom Profiles | available |
| Self Service categories | available (read-only; Iru exposes no write) |
| Custom Apps | planned |
| In-House Apps | not planned |
Earlier releases left authoring to iructl on the
reasoning that content authoring and fleet querying are different problems. The querying half of
that still holds. The authoring half rested on the assumption that the hard part of authoring is
talking to the API — and it is not. The hard part is the repository side: what a component looks
like on disk, which fields a human owns and which the vendor assigns, how a pull reconciles with a
working tree. Those are decisions a repository has to make for itself.
So the seam moved. irusdk owns the API and has no opinion about your filesystem; your own tooling
owns the repository.
The durability argument against this is real and is worth keeping visible: iructl is maintained
by Iru, so when the API changes, the people who changed it ship the fix. Adopting authoring here
means accepting on-call for that drift. If you do not need repository-side control, iructl is
still the shorter path.
| Task | Tool |
|---|---|
| Upload a Custom App package | iructl |
| Declaratively assign library items to blueprints | iructl |
| Read or author Custom Scripts and Profiles | irusdk |
| Find every Mac on an outdated OS | irusdk |
| Report FileVault or compliance state across the fleet | irusdk |
| Lock, erase, or restart a device | irusdk |
| Build a dashboard, Slack bot, or scheduled report | irusdk |
Documentation
Full documentation lives at irusdk.readthedocs.io.
License
Apache-2.0. See LICENSE.
Release files for irusdk 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 | |
|---|---|---|---|
| irusdk-0.2.0.tar.gz | 150.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| irusdk-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 214.6 kB
Release files / irusdk-0.2.0.tar.gz
| Download URL | irusdk-0.2.0.tar.gz |
|---|---|
| Size | 150.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b7abc70c3f9c4844450efab4ff1b29ffd58d07d8a34f6da772df0b097f2eda4
|
|
BLAKE2b-256 checksum How to use checksums |
690e6962a61161ed38a1615807f8ff8de1e59d962e1a0e44c7e49c3b36db1146
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 19, 2026.
Transparency logRelease files / irusdk-0.2.0-py3-none-any.whl
| Download URL | irusdk-0.2.0-py3-none-any.whl |
|---|---|
| Size | 64.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
80486886f59799c0529a97fbdc34345770fb0c9d02c30a74dce975782283ef73
|
|
BLAKE2b-256 checksum How to use checksums |
e216ea4bcaa333d988c2e754db4b207c8b5a8c2525618dd2ae596742815197ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 19, 2026.
Transparency log