Python SDK for the remit.md universal AI payment protocol
Project description
remit.md Python SDK
Skill MD · Docs · Agent Spec
Universal payment protocol for AI agents - Python client library.
Installation
pip install remitmd
With framework integrations:
pip install remitmd[langchain] # LangChain tools
pip install remitmd[crewai] # CrewAI tools
pip install remitmd[autogen] # AutoGen tools
pip install remitmd[openai-agents] # OpenAI Agents tools
Quickstart
from remitmd import Wallet
wallet = Wallet.from_env() # REMITMD_KEY, REMITMD_CHAIN
tx = await wallet.pay_direct("0xRecipient...", 1.50, memo="inference fee")
print(tx.tx_hash)
That's it. USDC approval is handled automatically.
Local Signer (Recommended)
The local signer delegates key management to remit signer, a localhost HTTP server that holds your encrypted key. Your agent only needs a URL and token - no private key in the environment.
export REMIT_SIGNER_URL=http://127.0.0.1:7402
export REMIT_SIGNER_TOKEN=rmit_sk_...
# Explicit
signer = await HttpSigner.create(url, token)
wallet = Wallet(signer=signer)
# Or auto-detect from env (recommended)
wallet = await Wallet.with_signer() # reads REMIT_SIGNER_URL + REMIT_SIGNER_TOKEN
await Wallet.with_signer() for local signer, Wallet.from_env() for raw key. Priority: REMIT_SIGNER_URL > OWS_WALLET_ID > REMITMD_KEY.
Secure Wallet with OWS
The Open Wallet Standard replaces raw private keys with encrypted local storage and policy-gated signing. Keys never leave the vault - the SDK signs through OWS's FFI layer.
Setup
# Install OWS
pip install open-wallet-standard
# or: curl -fsSL https://docs.openwallet.sh/install.sh | bash
# Create a wallet + policy + API key in one command
ows wallet create --name remit-my-agent
Or use the Remit CLI which does all of this automatically:
remit init # creates wallet, chain-lock policy, API key, prints MCP config
Usage
from remitmd import Wallet, OwsSigner
# Option 1: Direct signer construction
signer = OwsSigner(wallet_id="remit-my-agent", ows_api_key=os.environ.get("OWS_API_KEY"))
wallet = Wallet(signer=signer, chain="base")
# Option 2: Environment-based (set OWS_WALLET_ID + OWS_API_KEY)
signer = OwsSigner(
wallet_id=os.environ["OWS_WALLET_ID"],
ows_api_key=os.environ.get("OWS_API_KEY"),
)
wallet = Wallet(signer=signer)
Everything works the same - payments, permits, x402:
tx = await wallet.pay_direct("0xRecipient...", 1.50, memo="inference fee")
Environment Variables
| Variable | Purpose | Required |
|---|---|---|
OWS_WALLET_ID |
OWS wallet name or UUID | Yes (for OWS path) |
OWS_API_KEY |
API key token for headless signing | Recommended |
REMITMD_CHAIN |
"base" or "base-sepolia" |
No (defaults to "base") |
Install with OWS support
pip install remitmd[ows]
Custom Signer
Implement the Signer ABC for custom signing backends:
from remitmd import Signer, Wallet
class MySigner(Signer):
def get_address(self) -> str:
return "0x..."
async def sign_typed_data(self, domain, types, value) -> str:
return "0x..."
wallet = Wallet(signer=MySigner())
Payment Models
Direct Payment
tx = await wallet.pay_direct("0xRecipient...", 5.00, memo="AI task")
Escrow
from remitmd import Invoice
invoice = Invoice(to="0xContractor...", amount=100.00, memo="Code review")
escrow = await wallet.pay(invoice)
# Work happens...
await wallet.release_escrow(escrow.id) # pay the contractor
# or
await wallet.cancel_escrow(escrow.id) # refund yourself
Metered Tab (off-chain billing)
tab = await wallet.open_tab("0xProvider...", limit=50.0, per_unit=0.003)
# Hundreds of off-chain debits - zero gas, instant
# (provider calls debit on their side)
# One on-chain settlement when done
await wallet.close_tab(tab.id)
Payment Stream
stream = await wallet.open_stream("0xWorker...", rate=0.001, max_total=10.0)
# Worker receives 0.001 USDC/second
await wallet.close_stream(stream.id)
Bounty
bounty = await wallet.post_bounty(
amount=25.0,
task="Summarise top 10 EIPs of 2025",
deadline=1700000000,
)
# Any agent can submit work; you decide the winner
await wallet.award_bounty(bounty.id, "0xWinner...")
Security Deposit
deposit = await wallet.place_deposit("0xCounterpart...", amount=100.0, expires=86400)
Testing with MockRemit
MockRemit gives you a zero-network, zero-latency test double. No API key needed.
import pytest
from remitmd import MockRemit
@pytest.fixture
def wallet():
mock = MockRemit()
return mock.wallet("0xAgent...")
async def test_agent_pays(wallet):
mock = wallet._mock # access the underlying mock
tx = await wallet.pay_direct("0xProvider...", 0.003)
assert mock.was_paid("0xProvider...", 0.003)
All Methods
# Contract discovery (cached per session)
contracts = await wallet.get_contracts() # dict
# Direct payment
await wallet.pay_direct(to, amount, memo="") # Transaction
# Escrow
await wallet.pay(invoice) # Escrow
await wallet.claim_start(invoice_id) # Escrow
await wallet.submit_evidence(invoice_id, uri) # Escrow
await wallet.release_escrow(invoice_id) # Escrow
await wallet.release_milestone(invoice_id, index) # Escrow
await wallet.cancel_escrow(invoice_id) # Escrow
# Tabs
await wallet.open_tab(to, limit, per_unit, expires=86400) # Tab
await wallet.close_tab(tab_id, final_amount=0, provider_sig="0x") # Tab
await wallet.charge_tab(tab_id, amount, cumulative, call_count, provider_sig) # TabCharge
# Tab provider (signing charges)
sig = await wallet.sign_tab_charge(tab_contract, tab_id, total_charged, call_count) # str
# Streams
await wallet.open_stream(to, rate, max_total) # Stream
await wallet.close_stream(stream_id) # Transaction
# Bounties
await wallet.post_bounty(amount, task, deadline, max_attempts=10) # Bounty
await wallet.submit_bounty(bounty_id, evidence_hash, evidence_uri=None) # dict
await wallet.award_bounty(bounty_id, submission_id) # Bounty
# Deposits
await wallet.place_deposit(to, amount, expires) # Deposit
await wallet.return_deposit(deposit_id) # Transaction
# Status & analytics
await wallet.status() # WalletStatus
# Webhooks
await wallet.register_webhook(url, events, chains=None) # Webhook
# Operator links (optional: messages=[], agent_name="")
await wallet.create_fund_link() # LinkResponse
await wallet.create_withdraw_link(messages=["Withdraw"], agent_name="my-agent") # LinkResponse
# Testnet
await wallet.mint(amount) # dict {tx_hash, balance}
# x402 (HTTP 402 auto-pay)
response, payment = await wallet.x402_fetch(url, max_auto_pay_usdc=0.10)
Error Handling
All errors are RemitError with machine-readable codes and actionable details:
from remitmd import RemitError
try:
await wallet.pay_direct("0xRecipient...", 100.00)
except RemitError as e:
print(e.code) # "INSUFFICIENT_BALANCE"
print(e.message) # "Insufficient USDC balance: have $5.00, need $100.00"
# Enriched errors include details with actual numbers:
# e.details = {"required": "100.00", "available": "5.00",
# "required_units": 100000000, "available_units": 5000000}
Chains
Wallet(private_key=key, chain="base") # Base mainnet (default)
Wallet(private_key=key, chain="base-sepolia") # Base Sepolia testnet
Advanced: Manual Permits
All payment methods auto-sign EIP-2612 USDC permits internally. If you need explicit control (custom spenders, pre-signed permits, multi-step workflows), you can sign and pass them manually:
contracts = await wallet.get_contracts()
permit = await wallet.sign_permit(contracts["router"], 5.0)
tx = await wallet.pay_direct("0xRecipient...", 5.00, permit=permit)
The spender must match the contract handling the payment:
| Payment type | Spender |
|---|---|
| Direct | contracts["router"] |
| Escrow | contracts["escrow"] |
| Tab | contracts["tab"] |
| Stream | contracts["stream"] |
| Bounty | contracts["bounty"] |
| Deposit | contracts["deposit"] |
For lower-level control over nonce, deadline, and USDC address:
permit = await wallet.sign_usdc_permit(
spender=contracts["router"],
value=5_000_000, # raw USDC base units (6 decimals)
deadline=int(time.time()) + 3600,
nonce=0,
)
License
MIT - see LICENSE
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 remitmd-0.1.9.tar.gz.
File metadata
- Download URL: remitmd-0.1.9.tar.gz
- Upload date:
- Size: 63.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a91a515264e90a98a9062146a2e1645a0d6e231c07d7ebf4cf8a70835f99d446
|
|
| MD5 |
8f832c33cbcf84e6d0dcbb3041d14f26
|
|
| BLAKE2b-256 |
754c5808eeaed081996a11e8ed8da496b9f853238a3ec6ac999465829674c9da
|
Provenance
The following attestation bundles were made for remitmd-0.1.9.tar.gz:
Publisher:
publish.yml on remit-md/sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remitmd-0.1.9.tar.gz -
Subject digest:
a91a515264e90a98a9062146a2e1645a0d6e231c07d7ebf4cf8a70835f99d446 - Sigstore transparency entry: 1188526405
- Sigstore integration time:
-
Permalink:
remit-md/sdk@48ee327535bd884086df910ac664b466cca8cd37 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/remit-md
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@48ee327535bd884086df910ac664b466cca8cd37 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file remitmd-0.1.9-py3-none-any.whl.
File metadata
- Download URL: remitmd-0.1.9-py3-none-any.whl
- Upload date:
- Size: 52.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e1976077ee40f4e3e3af7a5ad4ea3bc9ed823a14069e14a7063c66c584a1072
|
|
| MD5 |
e8676f180f36959fc99c16bf5a3f2761
|
|
| BLAKE2b-256 |
a2062ae0cc81da73846341c8a84ebbe3fc95227973e2205f683cf95ddb5dd415
|
Provenance
The following attestation bundles were made for remitmd-0.1.9-py3-none-any.whl:
Publisher:
publish.yml on remit-md/sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remitmd-0.1.9-py3-none-any.whl -
Subject digest:
3e1976077ee40f4e3e3af7a5ad4ea3bc9ed823a14069e14a7063c66c584a1072 - Sigstore transparency entry: 1188526410
- Sigstore integration time:
-
Permalink:
remit-md/sdk@48ee327535bd884086df910ac664b466cca8cd37 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/remit-md
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@48ee327535bd884086df910ac664b466cca8cd37 -
Trigger Event:
workflow_dispatch
-
Statement type: