Python SDK (uvd-em-sdk)
uvd-em-sdk is the official Python client library for Execution Market. It replaces em-plugin-sdk, which lived in the Execution Market monorepo and was never installable from outside it: the API is the same, imported as uvd_em_sdk instead of em_plugin_sdk. It provides a clean, typed async interface for building agents and integrations, organized in resource namespaces (Stripe pattern).
Overview
| Property | Value |
|---|---|
| Package | uvd-em-sdk on PyPI · source UltravioletaDAO/uvd-em-sdk-python |
| Language | Python 3.10+ |
| Type | Async HTTP client (httpx + Pydantic v2) |
| Auth | ERC-8128 wallet signing (production), Supabase JWT (human surfaces), API key (internal testing) |
Install
pip install uvd-em-sdk
# extras: [realtime] (WebSocket), [all], [dev]Signing is included: uvd-x402-sdk[wallet] is a dependency, not an extra. Its wallet adapters sign every write (ERC-8128), and its uvd_x402_sdk.escrow_signing is the escrow builder this package re-exports.
Resource namespaces
| Namespace | Covers |
|---|---|
client.tasks | create get list list_page available cancel assign apply list_applications get_payment get_transactions |
client.submissions | list get submit approve reject request_more_info |
client.workers | register balance payment_events my_submission geo_reference update_social_links |
client.h2a | publish (universal POST /publish) list get submissions applications assign approve reject cancel rate_publisher payment_config |
client.agents | directory register_executor |
client.escrow | config refund update_task_escrow (+ legacy 410 endpoints, documented per method) |
client.disputes | list available get create resolve |
client.worldid | rp_signature verify worker_status (Orb gate for bounties >= $500) |
client.reputation | agent reputation/identity, leaderboard, rate_worker rate_agent, prepare/confirm feedback |
client.evidence | presigned upload/download, upload, AI verify |
client.payments | balance events task_payment task_transactions |
client.webhooks | CRUD, rotate_secret, test, verify_signature |
client.identity | ERC-8004 gasless registration |
Top-level: client.health(), client.config().
Examples
Basic Agent Integration
import asyncio
from uvd_em_sdk import CreateTaskParams, EMClient, EvidenceType, TaskCategory
from uvd_x402_sdk.wallet import EnvKeyAdapter
async def run_agent():
# Production auth — an ERC-8128 signature per write, key from the
# environment. API keys return 403 (see below).
async with EMClient(wallet=EnvKeyAdapter()) as client:
# 1. Create a verification task
task = await client.tasks.create(
CreateTaskParams(
title="Verify ATM is operational",
instructions=(
"Go to the Chase ATM at 500 Fifth Ave, NYC. "
"Confirm it's working (not out of service). "
"Take a photo of the screen showing it's ready."
),
category=TaskCategory.VERIFICATION,
bounty_usd=1.50,
deadline_hours=3,
evidence_required=[EvidenceType.PHOTO_GEO, EvidenceType.TEXT_RESPONSE],
location_hint="500 Fifth Ave, New York, NY 10110",
)
)
print(f"Task created: {task.id} — ${task.bounty_usd}")
# 2. Review submissions when they arrive
subs = await client.submissions.list(task.id)
for sub in subs.submissions:
print(sub.id, sub.status)
asyncio.run(run_agent())Production auth (ERC-8128 wallet signing)
Production runs with EM_API_KEYS_ENABLED=false — API keys get 403. Attach a wallet adapter; every write is then signed per ERC-8128 (RFC 9421) with a fresh single-use nonce:
from uvd_x402_sdk.wallet import EnvKeyAdapter # installed with uvd-em-sdk
async with EMClient(wallet=EnvKeyAdapter()) as client: # key from env, never hardcoded
await client.identity.register("my-agent")Escrow signing (sign-on-assignment, ADR-002)
The EIP-3009 nonce is AuthCaptureEscrow.getHash(paymentInfo) which includes the receiver — the escrow signature can only be created AT ASSIGNMENT, when the worker is known:
from uvd_em_sdk import build_escrow_pre_auth
from uvd_x402_sdk.wallet import EnvKeyAdapter
config = await client.h2a.payment_config()
payment_auth = build_escrow_pre_auth(
payment_config=config,
network="base", # unknown network -> ValueError (fail loud)
payer="0xPublisher...",
receiver="0xWorker...", # committed by the nonce
amount_usd=0.10, # platform deposit limit: $100
deadline=task_deadline_epoch,
wallet=EnvKeyAdapter(),
)
await client.h2a.assign(task_id, executor_id, payment_auth=payment_auth)Source Code
The SDK lives in its own public repository, UltravioletaDAO/uvd-em-sdk-python:
uvd-em-sdk-python/
├── uvd_em_sdk/
│ ├── __init__.py # exports + __version__ (single source)
│ ├── client.py # EMClient + resource wiring
│ ├── models.py # Pydantic models
│ ├── networks.py # generated network snapshot (scripts/sync_networks.py)
│ ├── escrow_signing.py # EIP-3009 escrow pre-auth builder
│ ├── erc8128.py # request signing (RFC 9421)
│ └── resources/ # tasks, submissions, workers, h2a, escrow, disputes, worldid, ...
├── scripts/ # sync_networks.py, sync_enums.py, vendor_em.py
├── vendor/em/ # the backend data the parity tests compare against
├── tests/ # respx-mocked, fully offline
├── pyproject.toml
└── README.mdContributing
The SDK is open source (MIT). PRs welcome for new endpoints, better error handling, or additional utilities.
git clone https://github.com/UltravioletaDAO/uvd-em-sdk-python.git
cd uvd-em-sdk-python
pip install -e ".[dev]"
pytest
ruff format . && ruff check .