Python clients for the IndyKite platform REST APIs: the Identity Knowledge Graph (IKG), KBAC authorization (AuthZEN), ContX IQ knowledge queries, data capture, entity matching, and platform configuration.
- OpenAPI reference: https://openapi.indykite.com
- Developer guides: https://developer.indykite.com
- Python 3.14+
pip install indykite-sdk-pythonThe SDK uses the two standard IndyKite credential kinds, obtained from the IndyKite Hub (or created via the Config API):
| Credential | Used by | What it is | Environment variables |
|---|---|---|---|
| Application Agent | all data-plane clients (capture, authzen, ciq, data schema, entity matching) | the raw credential token itself (opaque string, sent as X-IK-ClientKey) |
INDYKITE_APPLICATION_CREDENTIALS (the token) or INDYKITE_APPLICATION_CREDENTIALS_FILE (file with the token) |
| Service Account | ConfigClient |
a JSON artifact (serviceAccountId, pre-issued token, private key), sent as Authorization: Bearer |
INDYKITE_SERVICE_ACCOUNT_CREDENTIALS (inline JSON) or INDYKITE_SERVICE_ACCOUNT_CREDENTIALS_FILE (path) |
export INDYKITE_APPLICATION_CREDENTIALS="ik1_..." # the app agent credential token, as issued
export INDYKITE_SERVICE_ACCOUNT_CREDENTIALS_FILE=/path/to/service-account-credentials.jsonCredentials can also be passed explicitly:
from indykite_sdk import CaptureClient, ConfigClient, Credentials
capture = CaptureClient("ik1_...") # data-plane clients take the raw token
config = ConfigClient(Credentials.from_file("service-account-credentials.json"))The service-account JSON's pre-issued token is used while valid; when it
expires the SDK self-signs a fresh JWT from the credential's private key
(privateKeyJWK or PKCS#8). The app-agent token is never a JWT the SDK mints —
it is sent exactly as issued.
Production defaults to https://eu.api.indykite.com; pass region="us" for
the US region, or point base_url= / INDYKITE_BASE_URL at another
environment (e.g. https://api.dev.indykite.xyz).
from indykite_sdk import AuthZENClient
with AuthZENClient() as client:
result = client.evaluation(("Person", "ada"), "CAN_DRIVE", ("Car", "kitt"))
print(result.decision) # True / False
# Which cars can ada drive?
cars = client.search_resource(("Person", "ada"), "CAN_DRIVE", "Car")
print([car.id for car in cars.results])from indykite_sdk import CaptureClient
with CaptureClient() as client:
client.upsert_nodes([
{
"external_id": "ada",
"type": "Person",
"is_identity": True,
"properties": [{"type": "email", "value": "ada@example.com"}],
},
{"external_id": "kitt", "type": "Car"},
])
client.upsert_relationships([
{
"type": "OWNS",
"source": {"external_id": "ada", "type": "Person"},
"target": {"external_id": "kitt", "type": "Car"},
},
])from indykite_sdk import CIQClient
with CIQClient() as client:
for record in client.execute_iter("gid:my-knowledge-query-id", input_params={"personId": "ada"}):
print(record.nodes)from indykite_sdk import ConfigClient
with ConfigClient() as config:
organization = config.read_current_organization()
project = config.create_project("my-project", organization.id, region="europe-west1")
app = config.create_application("my-app", project.id)
agent = config.create_application_agent("my-agent", app.id, ["Authorization", "Capture", "ContXIQ"])
credential = config.create_application_agent_credential(agent.id)
agent_credentials = credential.as_credentials() # shown once - store it securelyUpdates and deletes are guarded by etags (If-Match): read the resource, then
pass its .etag:
app = config.read_application(app_id)
config.update_application(app_id, etag=app.etag, display_name="Renamed")Every client has an async twin with identical methods:
from indykite_sdk import AsyncAuthZENClient
async with AsyncAuthZENClient() as client:
result = await client.evaluation(("Person", "ada"), "CAN_DRIVE", ("Car", "kitt"))The SDK always raises typed exceptions — no method returns None on failure:
from indykite_sdk import AuthZENClient, AuthenticationError, IndyKiteError
try:
with AuthZENClient() as client:
decision = client.evaluation(("Person", "ada"), "CAN_DRIVE", ("Car", "kitt"))
except AuthenticationError as error:
print(error) # includes method, URL, status, and an actionable hint
except IndyKiteError as error:
print(f"SDK call failed: {error}")Exceptions include BadRequestError (400), AuthenticationError (401),
PermissionDeniedError (403), NotFoundError (404), ETagMismatchError
(412), RateLimitError (429), InternalServerError (5xx),
RequestValidationError (client-side validation), and
IndyKiteConnectionError (network).
Idempotent requests (GET/PUT/DELETE) are retried automatically on 429/502/503/504
with exponential backoff; tune or disable via retries=RetryConfig(...) / retries=None.
Runnable scripts for every client live in examples/.
pipenv install --dev
pipenv run pytest # unit tests (mocked, no credentials needed)
pipenv run pytest -m integration # live tests (needs credentials, see tests/integration/conftest.py)
pre-commit run --all-files- Issues: https://github.com/indykite/indykite-sdk-python/issues
- Vulnerability reports: see responsible_disclosure.md
Licensed under the Apache License 2.0.