Skip to main content

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.

CI PyPI

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

Documentation · Protocol Spec · GitHub

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remitmd-0.1.9.tar.gz (63.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

remitmd-0.1.9-py3-none-any.whl (52.9 kB view details)

Uploaded Python 3

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

Hashes for remitmd-0.1.9.tar.gz
Algorithm Hash digest
SHA256 a91a515264e90a98a9062146a2e1645a0d6e231c07d7ebf4cf8a70835f99d446
MD5 8f832c33cbcf84e6d0dcbb3041d14f26
BLAKE2b-256 754c5808eeaed081996a11e8ed8da496b9f853238a3ec6ac999465829674c9da

See more details on using hashes here.

Provenance

The following attestation bundles were made for remitmd-0.1.9.tar.gz:

Publisher: publish.yml on remit-md/sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for remitmd-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 3e1976077ee40f4e3e3af7a5ad4ea3bc9ed823a14069e14a7063c66c584a1072
MD5 e8676f180f36959fc99c16bf5a3f2761
BLAKE2b-256 a2062ae0cc81da73846341c8a84ebbe3fc95227973e2205f683cf95ddb5dd415

See more details on using hashes here.

Provenance

The following attestation bundles were made for remitmd-0.1.9-py3-none-any.whl:

Publisher: publish.yml on remit-md/sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page