Python reference library for consuming ia.json files — the universal standard for AI interaction with websites
Project description
iajson
Python reference library for consuming ia.json files -- the universal standard for AI interaction with websites.
Installation
# Install from GitHub
pip install "iajson @ git+https://github.com/Dandte/ai.json.git#subdirectory=libraries/python"
Requires Python 3.10+. The only runtime dependency is httpx.
Quick start
Synchronous
from iajson import IaJsonClient
# Discover and connect to a site
client = IaJsonClient.discover("techstore.example.com")
# Inspect the site
print(client.site.name) # "TechStore"
print(client.site.type) # "ecommerce"
print(client.version) # "1.0.0"
print(client.capabilities) # {"read": True, "write": True, ...}
# List available endpoints
for ep in client.get_endpoints():
print(f"{ep.name} [{ep.method} {ep.path}] ({ep.level})")
# Filter by access level
public_endpoints = client.get_endpoints(level="public")
# Call a public endpoint
products = client.call("search_products", q="wireless headphones")
print(products)
Asynchronous
import asyncio
from iajson import IaJsonClient
async def main():
client = await IaJsonClient.adiscover("techstore.example.com")
products = await client.acall("search_products", q="wireless headphones")
print(products)
product = await client.acall("get_product", id="prod_abc123")
print(product)
asyncio.run(main())
Authentication
Signed-key authentication (protected endpoints)
If you already have credentials:
client = IaJsonClient.discover(
"techstore.example.com",
api_key="ia_live_abc123def456",
secret="sec_xyz789uvw012",
)
# Call a protected endpoint -- signing is automatic
inventory = client.call("get_inventory")
Or set credentials after discovery:
client = IaJsonClient.discover("techstore.example.com")
client.set_credentials(api_key="ia_live_abc123def456", secret="sec_xyz789uvw012")
inventory = client.call("get_inventory")
Agent registration
The full registration flow (Section 5.1 of the ia.json spec):
from iajson import IaJsonClient, AgentInfo
client = IaJsonClient.discover("techstore.example.com")
# Step 1: Send registration request
agent = AgentInfo(
name="My AI Assistant",
domain="myai.example.com",
webhook_url="https://myai.example.com/verify",
contact="admin@myai.example.com",
description="AI shopping assistant",
)
client.register(agent)
# Step 2: The site sends a verification code to your webhook_url.
# Handle that in your webhook handler.
# Step 3 & 4: Submit the verification code and receive credentials
verification_code = "vc_abc123def456" # received at your webhook
creds = client.complete_registration(verification_code)
print(creds.api_key) # "ia_live_..."
print(creds.secret) # "sec_..."
print(creds.expires_at) # "2026-05-12T00:00:00Z"
print(creds.permissions) # ["public", "protected"]
# Credentials are now stored on the client automatically
inventory = client.call("get_inventory")
OAuth2 (user_required endpoints)
from iajson import IaJsonClient
from iajson.auth.oauth import OAuth2Config, generate_pkce_challenge, build_authorization_url, exchange_code
client = IaJsonClient.discover("techstore.example.com")
# Parse OAuth2 config from the ia.json document
oauth_config = OAuth2Config.from_dict(client.document["auth"]["oauth2"])
# Generate PKCE challenge
pkce = generate_pkce_challenge()
# Build the authorization URL for the user to visit
auth_url = build_authorization_url(
oauth_config,
client_id="your_client_id",
redirect_uri="https://myai.example.com/callback",
scopes=["cart:read", "cart:write", "orders:write"],
state="random_csrf_token",
pkce=pkce,
)
print(f"Send user to: {auth_url}")
# After the user authorizes, exchange the code for a token
token = exchange_code(
oauth_config,
client_id="your_client_id",
client_secret="your_client_secret",
code="authorization_code_from_callback",
redirect_uri="https://myai.example.com/callback",
code_verifier=pkce.verifier,
)
# Set the token on the client
client.set_access_token(token.access_token)
# Now call user_required endpoints
cart = client.call("get_cart")
client.call("add_to_cart", product_id="prod_abc123", quantity=2)
Request signing
If you need to compute signatures manually:
from iajson import sign, create_signed_headers
# Low-level: compute a signature
signature = sign(
secret="sec_xyz789uvw012",
timestamp=1707753600,
body='{"product_id":"prod_123","quantity":2}',
)
# High-level: get a full set of auth headers
headers = create_signed_headers(
api_key="ia_live_abc123def456",
secret="sec_xyz789uvw012",
body='{"product_id":"prod_123","quantity":2}',
prefix="X-IA-",
algorithm="sha256",
)
# headers = {
# "X-IA-Key": "ia_live_abc123def456",
# "X-IA-Signature": "a1b2c3d4...",
# "X-IA-Timestamp": "1707753600",
# }
Discovery
Low-level discovery (without creating a client):
from iajson import discover, adiscover
# Synchronous
doc = discover("techstore.example.com")
print(doc["site"]["name"])
# Asynchronous
doc = await adiscover("techstore.example.com")
print(doc["api"]["base_url"])
Endpoint introspection
client = IaJsonClient.discover("techstore.example.com")
# Get a specific endpoint
ep = client.get_endpoint("search_products")
print(ep.name) # "search_products"
print(ep.method) # "GET"
print(ep.path) # "/products/search"
print(ep.level) # "public"
print(ep.description) # "Search products by keyword"
# Inspect parameters
for param in ep.parameters:
print(f" {param.name}: {param.type} (required={param.required})")
# q: string (required=True)
# min_price: number (required=False)
# max_price: number (required=False)
# Inspect body fields (for POST endpoints)
ep_order = client.get_endpoint("create_order")
for field in ep_order.body_fields:
print(f" {field.name}: {field.type} (required={field.required})")
Error handling
from iajson import (
IaJsonClient,
IaJsonError,
AuthenticationError,
DiscoveryError,
RateLimitError,
)
try:
client = IaJsonClient.discover("unknown-site.example.com")
except DiscoveryError as e:
print(f"Discovery failed: {e.message}")
print(f"Domain: {e.domain}")
print(f"HTTP status: {e.status_code}")
try:
result = client.call("get_inventory")
except AuthenticationError as e:
print(f"Auth failed: {e.message}")
print(f"Error code: {e.error_code}") # e.g. "invalid_signature"
except RateLimitError as e:
print(f"Rate limited! Retry after {e.retry_after} seconds")
except IaJsonError as e:
print(f"General error: {e.message}")
API reference
IaJsonClient
| Method | Description |
|---|---|
IaJsonClient.discover(domain) |
Fetch ia.json and create a client (sync) |
IaJsonClient.adiscover(domain) |
Fetch ia.json and create a client (async) |
client.call(endpoint, **params) |
Invoke an endpoint (sync) |
client.acall(endpoint, **params) |
Invoke an endpoint (async) |
client.get_endpoints(level=None) |
List endpoints, optionally filtered |
client.get_endpoint(name) |
Get a single endpoint by name |
client.register(agent_info) |
Start agent registration |
client.complete_registration(code) |
Finish registration with verification code |
client.sign(body) |
Compute a request signature |
client.set_credentials(key, secret) |
Set signed_key credentials |
client.set_access_token(token) |
Set an OAuth2 access token |
Properties
| Property | Type | Description |
|---|---|---|
client.site |
SiteInfo |
Parsed site metadata |
client.base_url |
str |
API base URL |
client.version |
str |
ia.json spec version |
client.capabilities |
dict |
Feature flags |
client.document |
dict |
Raw ia.json document |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file iajson-1.0.0.tar.gz.
File metadata
- Download URL: iajson-1.0.0.tar.gz
- Upload date:
- Size: 14.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51df2a7da7abd739e8b0e1adf9bfd7640a670598ab70b67df742a9b63f5d11c1
|
|
| MD5 |
fce3bd5b89a517426573c44ba856e803
|
|
| BLAKE2b-256 |
dc5cf57d7ef4e4377478895b317120cf0987a9ceb766167160cadbce89a81979
|
File details
Details for the file iajson-1.0.0-py3-none-any.whl.
File metadata
- Download URL: iajson-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55fd65edca4726fd8adaa03233177829640f99692c1110163f25b7662d9d68e4
|
|
| MD5 |
60817e789349eaee92788748f9c441aa
|
|
| BLAKE2b-256 |
2a0846ece9a8fdbbe00c2fe1a37f3334217347f34f0c7855d38365c4a91d46b3
|