Observed since 20 Oct, 20:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Python client for the Aether chain: ML-DSA-44 keys, payments, buying and selling paid APIs (x402 aether-memo / aether-prepaid) and the service directory.
pip install aether-chain-client
Python client for the Aether chain: ML-DSA-44 keys, sending and receiving AETH, buying from and selling paid APIs (x402 aether-memo, aether-prepaid and aether-pull) and the on-chain service directory. It talks to a node's CometBFT RPC (port 26657) only.
import os
from aether_client import AetherClient, Key, fetch_paid, find_services, rate_service, withdraw_prepaid
client = AetherClient("http://localhost:26657", "aether-testnet-1")
key = Key.from_mnemonic(os.environ["AETHER_MNEMONIC"]) # same address as `aetherd keys add` / `agentmcp`
sent = client.send(key, "aether1...", "0.5 AETH", memo="invoice-42")
done = client.wait_for_transaction(sent.hash) # confirmed | failed | pending (timeout)
# Retrying after an error: client.rebroadcast(sent.signed) -- never a second send().
res = fetch_paid(client, key, "https://api.example.com/forecast", max_amount="0.05 AETH", prepay="1 AETH")
# Or, where offered, pay from your own account under a capped, 7-day allowance the seller collects from later:
res2 = fetch_paid(client, key, "https://api.example.com/forecast", max_amount="0.05 AETH", pull_allowance="1 AETH")
services = find_services(client, query="weather", max_price="0.1 AETH", trusted=[owner_address])
# services[i].reputation: payments, payers, ratings (can be faked), trusted_ratings (can't)
# res.receipt: the seller's signed receipt and whether it matches exactly what was sent and received
rate_service(client, key, "https://api.example.com", 5) # only raters who paid a service count
back = withdraw_prepaid(client, key, "https://api.example.com", withdrawal_id="w1") # unspent prepaid balance
aether_client.x402.ExactAetherScheme pays the standard x402 v2 exact scheme with the
x402 package's clients (x402ClientSync, x402_requests); the setup is in
docs/X402.md. It signs a
send of exactly what the 402 asks, and the server's facilitator broadcasts it.
AetherToolkit gives an agent seven tools: check a balance, check a transaction,
find paid APIs in the on-chain directory, quote an AETH to OSMO swap on Osmosis
testnet, send a payment, call a paid API (paying it), and ask the testnet faucet
for funds. Each framework gets them in its own form:
pip install "aether-chain-client[langchain]" # or [openai-agents], [crewai], [llamaindex]
import os
from aether_client import AetherClient, Key
from aether_client.agent_tools import AetherToolkit
client = AetherClient("https://rpc.157-245-252-221.sslip.io", "aether-testnet-1")
kit = AetherToolkit(client, Key.from_mnemonic(os.environ["AETHER_MNEMONIC"]),
max_per_payment="0.1 AETH", daily_budget="1 AETH")
tools = kit.langchain() # LangChain / LangGraph: create_react_agent(model, tools)
tools = kit.openai_agents() # OpenAI Agents SDK: Agent(name=..., tools=tools)
tools = kit.crewai() # CrewAI: Agent(..., tools=tools)
tools = kit.llamaindex() # LlamaIndex: FunctionAgent(tools=tools, llm=...)
specs = kit.tool_specs() # anything else: OpenAI-style function specs ("anthropic" for Messages API tools)
result = kit.call(name, arguments) # ... and the answer to the model's tool call
max_per_payment, or
past daily_budget in a rolling 24 hours, is refused before anything is signed.
kit.spending_status() shows what's left. Paid API calls count what they paid.send_payment takes an idempotency_key; the same key
returns the first result instead of paying again.AetherToolkit(client) offers only the balance,
transaction, directory and swap-quote tools.aether_quote_swap reads Osmosis's own estimate for the AETH/OSMO
pool (1370) and gives the OSMO out, the cost in fees and price impact, and a
minOutput for a slippage. It is on for aether-testnet-1; osmosis_rest=[...]
names other Osmosis REST endpoints and osmosis_rest=[] turns it off. It only
quotes: the swap itself is agentmcp's swap_aeth (see docs/OSMOSIS-POOL.md).{"error": {"code", "message"}}, so
the model sees what went wrong instead of the run stopping.Tested with langchain-core 1.6, openai-agents 0.23, crewai 1.6 and llama-index-core 0.14.
Charge per request from a Python service -- all three payment schemes, the /.well-known/x402 manifest for the service directory, and withdrawals of unspent prepaid balances. Compatible with the Go paywall and every Aether buyer.
import os
from fastapi import FastAPI, Request
from aether_client import AetherClient, Key, Paywall
client = AetherClient("http://localhost:26657", "aether-testnet-1")
pw = Paywall(client, "aether1...", "0.01 AETH", name="Weather", description="Forecasts by city",
prepaid_ledger="ledger.json", # customers' balances: back it up
min_deposit="0.1 AETH",
payout_key=Key.from_mnemonic(os.environ["PAYOUT_MNEMONIC"]), # pays withdrawals; keep a small float in it
receipt_key=payee_key, # sign a receipt for every paid response (or a delegated key + receipt_delegation)
pull_collector_key=Key.from_mnemonic(os.environ["COLLECTOR_MNEMONIC"]), pull_credit="1 AETH") # aether-pull: needs no funds
pw.start_collecting() # collects what aether-pull buyers owe, in batches
api = FastAPI()
@api.get("/forecast")
async def forecast(request: Request):
return {"paid_by": request.scope["aether"].payer}
app = pw.asgi(api, free=["/health"]) # Flask/Django: app.wsgi_app = pw.wsgi(app.wsgi_app); who paid: environ["aether.payment"]
The ledger is one JSON file (the Go paywall's format) for one process. Chain lookups block, so the ASGI adapter runs them in a thread.
Amounts always carry a unit ("1.5 AETH", "1500000uaeth").
USDC. AetherClient(rpc, chain_id, usdc_channel="channel-N") (Aether's end of its channel to Noble) also knows USDC: Noble's uusdc over exactly that channel, never a lookalike that arrived another way. For USDC that arrives another route, give its denom trace and its denom on the issuing chain instead: usdc_path="transfer/channel-2", usdc_base_denom="erc20:0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d", usdc_issuer="Injective" (usdc_base_denom defaults to uusdc). Then send(key, to, "5 USDC") sends USDC, balances(address) lists each asset, wait_for_payment matches in the asset of min_amount, and fetch_paid pays services priced in USDC with max_amount (and prepay / pull_allowance) in USDC; an amount in another asset than the service charges is refused with ASSET_MISMATCH before anything is paid. Results carry asset, amount, balance, owed and allowance in that asset's base units; the *_uaeth fields are set only for AETH. Without the channel, "5 USDC" is an unknown unit. The seller kit charges USDC too: Paywall(client, pay_to, "0.05 USDC", usdc_channel="channel-N") charges Noble USDC for everything (payments, deposits and balances, pull allowances and collections, withdrawals), min_deposit and pull_credit must then be in USDC, and 402s, the manifest and receipts carry the asset exactly as cmd/paywall's do.
Tests: python -m pytest tests (checked against ../testdata/vectors.json, generated by the Go code).
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.2.14 | 18 Oct 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 20:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:d7c06051de5a6d8d994c42dd4ff0d8fde57802700721df2b3c8cb0e51a047658