Skip to main content

poh-sdk

Python SDK for the Decentralized Artificial Intelligence network.

Install

pip install poh-sdk

# For transaction signing:
pip install poh-sdk cryptography

Quick start

import asyncio
from poh_sdk import DAIClient

async def main():
    async with DAIClient("https://miner.iamai.kg") as dai:
        result = await dai.scan("0xabc...")
        print(result.result)   # True = human, False = bot, None = inconclusive

asyncio.run(main())

Sync usage

Use DAIClient.sync(...) to get a synchronous wrapper exposing the same methods (no _sync suffix) without await:

from poh_sdk import DAIClient

dai = DAIClient.sync("https://iamai.kg")
result = dai.scan("0xabc...")
balance = dai.get_balance("dai...")

Natural language jobs

Skill jobs always require a fee — pass budget (DAI), wallet_address, and private_key_pem in AskOptions so the SDK can sign the payment. The node verifies the signature and debits the fee before it will run the job at all; it rejects the request outright (no job ever runs) without a valid signed payment. Pass currency in AskOptions to pay the fee in a stablecoin (see Stablecoins).

from poh_sdk import AskOptions

async with DAIClient("https://iamai.kg") as dai:
    options = AskOptions(budget=0.5, wallet_address="dai...", private_key_pem=my_private_key)

    # Submit a question
    ref = await dai.submit_job(
        "What does vitalik.eth write about on Paragraph?",
        options,
    )

    # Wait for the answer
    result = await dai.poll_job_result(ref.job_id)
    print(result.output)       # skill-specific structured data
    print(result.nl_response)  # LLM natural-language answer

    # One-liner convenience
    result = await dai.ask_and_wait("What NFTs does gmoney.eth hold?", options)

Compute jobs (your own model + dataset)

Run inference with a model of your choice, optionally grounded in a Hugging Face dataset already installed on the node. Like skill jobs, compute jobs are never free — run_compute always signs a fee payment.

from poh_sdk import ComputeOptions

async with DAIClient("https://iamai.kg") as dai:
    ref = await dai.run_compute("Summarize the top 5 rows", ComputeOptions(
        model="llama3.1:8b",
        dataset="some-org/some-dataset",  # optional
        budget=0.5,                       # DAI (or `currency` display units)
        wallet_address="dai...",
        private_key_pem=my_private_key,
    ))
    result = await dai.poll_job_result(ref.job_id)
    print(result.output)

Before either of these will work, the wallet's signing key must be registered with the node once via register_signing_key() / register_key_pair() — the node has no way to verify a signature for a key it has never seen.

Estimating a job's fee

Before paying for a job, ask the node what it will cost — the eth_estimateGas of DAI. Send the same fields you would submit (prompt, attachments, a skill, MCP tools, a dataset). The node sizes the whole pipeline — attachment text, skill and MCP output, dataset rows, planner and synthesis calls — and returns the AI tokens it will use, the minimum fee it accepts, and a recommended budget. It is read-only: nothing runs and nothing is paid.

from poh_sdk import ChatAttachment, EstimateOptions

async with DAIClient("https://iamai.kg") as dai:
    est = await dai.estimate(
        "Summarize this report and compare it with the latest news",
        EstimateOptions(
            attachments=[ChatAttachment(name="report.md", content=report_text)],  # text is inlined and measured
            # skill_id="web_search", mcp=["shop__search"], dataset="some-org/some-dataset",
            # currency="aiKGS", max_output_tokens=512, route=False,
        ),
    )

    est.fees.minimum.raw        # μDAI the node will accept, at minimum
    est.fees.recommended.raw    # μDAI to escrow — covers the worst case
    est.total_tokens            # TokenRange(min=…, max=…)
    est.breakdown               # what each part contributed, and how sure that is

    # run_compute takes DAI; estimate returns μDAI
    budget = est.fees.recommended.raw / 1e9

What comes back:

Field Meaning
prompt_tokens, output_tokens, skill_compute_tokens, total_tokens Each a TokenRange(min, max)
breakdown Every contributor, tagged measured (counted exactly — prompt, attachment text, dataset rows), bounded (capped by the executing code — what a skill fetched, an MCP tool returned) or assumed
calls Each model call the pipeline makes (planner, skill answer, synthesis…)
fees.minimum (FeeQuote) The lowest fee the node accepts — bids below it are rejected (/job floors at a fixed amount, chat at the prompt alone)
fees.recommended Covers the pipeline's worst case, never below the minimum. Escrow this
route Which pipeline would run; predicted: true means it comes from the deterministic router — the live model-planner may choose differently
outputCap, warnings Whether the budget caps output, and anything unusual (images are not billed; job output is capped at 512 tokens)

Amounts are in raw units of the fee currency (μDAI for DAI; 1 DAI = 1e9 μDAI), so divide by 1e9 for runCompute's budget. For a non-DAI currency the price is quoted off the live P2P book; if nothing quotes that pair the quote says unavailable instead of inventing a number, and a DAI figure is returned alongside.

Needs a node newer than 0.4.36 (it adds POST /api/estimate); older nodes answer 404. estimate is read-only, so — unlike the other POST methods — it works against remote nodes without a local_base_url.

Wallet / blockchain

async with DAIClient("https://iamai.kg") as dai:
    # Balance (μDAI — divide by 1e9 for DAI)
    bal = await dai.get_balance("dai...")
    print(bal.balance / 1e9, "DAI")

    # Nonce
    nonce = await dai.get_nonce("dai...")

    # Transaction history (balance journal)
    history = await dai.get_transaction_history("dai...", limit=50)
    for entry in history.entries:
        print(entry.tx_hash, entry.delta)

    # Raw transaction records involving an address
    txs = await dai.get_transactions("dai...")

    # Miner info
    info = await dai.get_miner_info()
    print(info.model, info.reputation)

Signing & transactions

from poh_sdk import (
    generate_key_pair,
    build_transfer,
    sign_transaction,
    create_signing_proof,
)

# 1. Generate a keypair — address is derived from the signing public key
private_key_pem, public_key_pem, my_address = generate_key_pair()

# 2. Register the public key with your local node (one-time)
async with DAIClient(
    "https://miner.iamai.kg",
    local_base_url="http://127.0.0.1:3456",
) as dai:
    await dai.register_signing_key(
        my_address, public_key_pem, create_signing_proof(my_address, private_key_pem)
    )

    # 3. Build, sign, and submit a transfer
    nonce_resp = await dai.get_nonce(my_address)
    tx     = build_transfer(my_address, recipient, amount_dai=5.0, nonce=nonce_resp.nonce + 1)
    signed = sign_transaction(tx, private_key_pem)
    result = await dai.submit_transaction(signed)
    print(result.tx_hash)

    # One-liner convenience (fetches nonce automatically)
    result = await dai.transfer(my_address, recipient, 5.0, private_key_pem)

register_key_pair(KeyPair(...)) does the same registration from a KeyPair, deriving the proof automatically and also publishing the wallet's X25519 encryption key (see Chat record encryption). To replace an already-registered key, sign a create_rotation_proof(address, new_signing_public_key, existing_private_key_pem) with the current key and pass it as rotation_proof.

Stablecoins (multi-currency)

Five regional stablecoins ride alongside DAI: aiGEL, aiKGS, aiAMD, aiETB, aiBTN (2 decimals — 1 unit = 100 raw; DAI keeps 9).

# Transfer 12.50 aiGEL — build + sign + submit manually
# (transfer() itself is DAI-only; it has no currency parameter)
tx = build_transfer(from_addr, to, 12.5, nonce + 1, currency="aiGEL")
signed = sign_transaction(tx, private_key_pem)
await dai.submit_transaction(signed)

# Pay a compute job in aiKGS — the miner receives exactly aiKGS
ref = await dai.run_compute("Summarize…", ComputeOptions(
    model="qwen3-1.7b", budget=5.0, currency="aiKGS",
    wallet_address=addr, private_key_pem=key,
))

DAI transactions/job payments hash exactly as before (currency enters the signed preimage only when non-DAI) — existing integrations are unaffected.

Chat record encryption

Public-job chat records (promptCipher / replyCipher) are sealed to the requester wallet's X25519 key, derived deterministically from its Ed25519 signing key. register_key_pair() publishes the encryption key automatically.

from poh_sdk import derive_encryption_keypair, is_envelope, unseal

keys = derive_encryption_keypair(private_key_pem)
# keys["publicKeyB64"], keys["privateScalarB64"]

if is_envelope(record["promptCipher"]):
    prompt = unseal(record["promptCipher"], keys["privateScalarB64"])

Bulk scans

async with DAIClient("https://iamai.kg") as dai:
    job = await dai.scan_bulk(["0xaaa", "0xbbb", "0xccc"])

    # Stream progress
    async for snap in dai.watch_job(job.job_id):
        print(f"{snap.percent:.0f}% done")

    # Or wait in one call
    final = await dai.scan_and_wait(["0xaaa", "0xbbb"])

Multi-node

dai = DAIClient(nodes=[
    "https://miner.iamai.kg",
    "https://iamai.kg",
    "https://miner.iamai.kg",
])
# Automatically picks the fastest responding node

API reference

Scanning

Method Description
scan(input, opts?) Single-address scan
scan_bulk(inputs, opts?) Submit bulk scan job
get_job(job_id) Current snapshot of a bulk scan job
poll_job(job_id, opts?) Poll until job completes
watch_job(job_id, opts?) Async generator of job snapshots
scan_and_wait(inputs, opts?) Bulk + poll in one call
get_brain_verdict(brain_key) AI verdict
poll_brain_verdict(brain_key, opts?) Poll until verdict resolves
scan_and_verdict(input, scan_opts?, brain_opts?) Scan + verdict in one call

Signal methods

Method Description
get_methods(wallet_address?) List signal verification methods, ordered by vote score
get_method(method_id) Fetch a single signal method by ID

Natural language jobs

Method Description
submit_job(question, options?) Submit NL question (AskOptions). Skill jobs always require a fee — pass budget, wallet_address, private_key_pem; optional currency (stablecoin fee).
run_compute(prompt, options) Submit a job that runs a specific model (and optional dataset); ComputeOptions (optional currency, job_id). Always requires a fee.
estimate(prompt, options?) Estimate a job's or chat's fee before paying (EstimateOptions) — tokens, minimum fee, recommended budget. Read-only; works on remote nodes.
get_job_status(job_id) Poll status
get_job_result(job_id) Fetch result
poll_job_result(job_id, opts?) Poll until result ready
ask_and_wait(question, ask_options?, poll_options?) Submit + wait

Wallet / blockchain

Method Description
get_balance(address) Balance in μDAI
get_nonce(address) Account nonce (+ pending_nonce when mempool txs reserve higher)
get_transaction_history(address, limit) Balance journal history
get_transactions(address) Raw transaction records involving an address
get_pending_transactions() Mempool pending txs
submit_transaction(tx) Submit signed tx
register_signing_key(addr, pub_key_pem, proof, rotation_proof?, encryption_public_key?) Register signing key (+ optional X25519 encryption key)
register_key_pair(key_pair, rotation_proof?) Register a KeyPair; auto-derives proof + encryption key
transfer(from, to, amount_dai, private_key_pem, fee?, memo?) Full transfer (DAI only — use build_transfer(currency=...) for stablecoins)

Signing utilities

Function Description
generate_key_pair() Fresh Ed25519 keypair → (private_pem, public_pem, address)
derive_address_from_signing_key(public_key_pem) Canonical dai… address for a signing public key
sign_data(message, private_key_pem) Sign arbitrary data → base64
create_signing_proof(address, private_key_pem) Proof for key registration
create_rotation_proof(address, new_signing_public_key, existing_private_key_pem) Proof for replacing a registered key
build_transfer(from, to, amount_dai, nonce, fee?, memo?, currency?) Build unsigned tx (amount in display units of currency)
sign_transaction(tx, private_key_pem) Sign a DAITxData
compute_tx_hash(...) SHA-256 tx hash hex
compute_job_payment_hash(...) Canonical hash for a job fee payment (used internally by submit_job/run_compute)
sign_job_payment(...) Sign a job fee payment proof (used internally by submit_job/run_compute)

Chat encryption utilities

Function Description
derive_encryption_keypair(stable_secret) X25519 keypair dict (publicKeyB64, privateScalarB64) derived from the signing key
seal(recipient_pub_b64, plaintext) Encrypt to a sealed envelope dict
unseal(envelope, private_scalar_b64) Decrypt a sealed envelope
seal_json(recipient_pub_b64, obj) / unseal_json(envelope, private_scalar_b64) JSON convenience wrappers
is_envelope(x) Check whether a value is a sealed envelope

Node info

Method Description
get_node_info() Node metadata
get_miner_info() Miner details
list_skills() Available skills

Differences from the JS SDK

The Python SDK does not (yet) implement some features present in @poh_network/sdk:

  • chat() — no free-form chat endpoint wrapper
  • submit_feedback() — no job star-rating
  • get_assets() — no asset-registry / gas-price endpoint wrapper
  • get_balance() returns only the μDAI balance (no stablecoin assets map)
  • transfer() has no currency parameter — stablecoin transfers go through build_transfer(currency=...) + submit_transaction()
  • TxSubmitResult has no idempotent flag
  • No pick_strategy option (multi-node always picks the fastest node)

License

MIT

Release files for poh-sdk 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for poh-sdk 0.7.0
File Size Uploaded
poh_sdk-0.7.0.tar.gz 32.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for poh-sdk 0.7.0
File Interpreter ABI Platform
poh_sdk-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.0 kB

Release files / poh_sdk-0.7.0.tar.gz

Download URL poh_sdk-0.7.0.tar.gz
Size 32.7 kB
Tags Source
SHA-256 checksum
How to use checksums
10344bb87843e75f7e88201e0bbe5b65fbb11351727918b4d7f12426479ad77d
BLAKE2b-256 checksum
How to use checksums
37d7c45a1dd100af0ac6a2b1aa14272d749e7a7197824f7dd4143a4caddbdefd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / poh_sdk-0.7.0-py3-none-any.whl

Download URL poh_sdk-0.7.0-py3-none-any.whl
Size 28.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9b729f1517fe66279a8434f3b1bdc58885d0a3f995db9eb1876a449e567ec14e
BLAKE2b-256 checksum
How to use checksums
37630a602604042bc8a1af414d8da413c49fa4ea0d4b421850a42c2ef6d8850e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page