Metadata-Version: 2.4
Name: doerflow
Version: 0.5.0
Summary: DoerFlow Agent Trading SDK (discover, quote, receipts)
Author: AgentSkillMesh
License: Polyform-Noncommercial-1.0.0
Project-URL: Homepage, https://docs.doerflow.dev
Project-URL: Repository, https://github.com/AgentSkillMesh/DoerFlow
Project-URL: Documentation, https://docs.doerflow.dev/developers/agent-trading-sdk
Keywords: doerflow,vibe-agent,agent-trading
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: sign
Requires-Dist: eth-account>=0.13; extra == "sign"
Dynamic: license-file

# DoerFlow Python SDK

REST client for Agent Trading (`/trading/*`, `/payments/*`). Install from this MetaRepo (editable); this README does not claim a published PyPI release.

```bash
pip install -e sdk/python
# EIP-712 session + receipt signing:
pip install -e "sdk/python[sign]"
# offline sign-loop tests (no live API):
python -m unittest discover -s sdk/python/tests -v
```

## Discover

```python
from doerflow import DoerFlowClient, verify_webhook

client = DoerFlowClient("http://localhost:13008/api/v1")
print(client.catalog()["skills"][0]["skillId"])
print(client.quote("0", 1)["amount"])
print(len(client.channels()["channels"]))  # 5
skill = client.register_provider_skill(
    "Acme", "http://127.0.0.1:9/hook", "10000", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
)
# keep skill["webhookSecret"]; verify_webhook(raw_body, signature, secret)
```

## Signed payment loop (FR-DEV-004)

`pip install 'doerflow[sign]'` then `catalog → quote → create_job → authorize_session → pay_quote` (and `apply_receipt_ledger` if the Vault accepted the receipt but the ledger did not move). EIP-712 domains match `@vibe-agent/shared/payments`: receipt `VibeAgent` / `1`, session `VibeAgent Session` / `1`, `verifyingContract=0x000…0`.

```python
import os
from doerflow import DoerFlowClient

client = DoerFlowClient("http://localhost:13008/api/v1", chain_id=84532)
# optional developer key (FR-DEV-001): Authorization Bearer + X-DoerFlow-Key
# client = DoerFlowClient("http://localhost:13008/api/v1", api_key=os.environ["DOERFLOW_API_KEY"])

quote = client.quote("0", 1)
job = client.create_job(quote["skillId"], 1)
client.authorize_session(
    owner_key=os.environ["OWNER_KEY"],
    session_key=os.environ["SESSION_KEY"],
    allowed_payees=[quote["payee"]],
    max_amount_per_call=quote["amount"],
    session_budget=quote["amount"],
)
paid = client.pay_quote(
    session_key=os.environ["SESSION_KEY"],
    quote=quote,
    resource_id=job["resourceId"],
)
if paid["submitted"].get("ledgerApplied") is False:
    client.apply_receipt_ledger(paid["submitted"]["receiptId"])
```

Helpers: `sign_receipt` / `sign_session_authorization`. `submit_receipt` returns API `data` (`ledgerApplied` / `ledgerError`); HTTP 200 can still have `ledgerApplied=false`. Do not resubmit the same signed body (Vault `DUPLICATE`); credit the ledger then `apply_receipt_ledger`.

Session helpers: `list_sessions()` / `revoke_session(session_id)`. Lab devices: `list_devices()` / `register_device` / `heartbeat_device` / `post_device_telemetry`. Ledger credit: `credit_ledger` / `credit_ledger_batch` (service JWT). Ledger nets: `list_ledger_nets` / `settle_ledger_net` / `create_ledger_bundle` (service JWT for settle/bundle). Payer stats: `payer_receipt_stats(payer)`. Payments disclosure/health: `payments_disclosure()` / `payments_health()` (distinct from `health()` → `/health`). Commercial preflight: `assert_commercial(address=None, escrow_wei=None)`. Onramp lab (not live charges): `onramp_health()` / `onramp_disclosure()` / `list_onramp_providers(country=None)` / `create_onramp_session(...)`. TypeScript client: `@vibe-agent/shared/sdk`. Lab smoke: `pnpm run smoke:m4` / `pnpm run smoke:channels`. Spec: `spec/DEVELOPER.md` · `spec/CHANNELS.md`.
