Skip to main content

PQSafe AgentPay Python SDK — post-quantum safe payments for AI agents

Project description

pqsafe-agent-pay

Python SDK for PQSafe AgentPay — post-quantum safe payments for AI agents.

Uses ML-DSA-65 (NIST FIPS 204) for signing. Works with LangChain, CrewAI, AutoGen, and custom Python agents.

Install

pip install pqsafe-agent-pay

Or for local development:

git clone https://github.com/PQSafe/pqsafe
cd pqsafe/python-sdk
pip install -e ".[dev]"

30-second example

from pqsafe import create_envelope, generate_keypair, pay, sign_envelope

# 1. Generate an ML-DSA-65 key pair (issuer/wallet owner)
keypair = generate_keypair()

# 2. Create a SpendEnvelope authorizing an AI agent to pay up to $10 USD
envelope = create_envelope(
    issuer="pq1" + "a" * 40,           # wallet owner's PQSafe address
    agent="my-ai-agent-v1",
    max_amount=10.00,
    currency="USD",
    allowed_recipients=["38873dbc-abfa-4ab5-be25-050496d4a0c3"],
    ttl_seconds=3600,
)

# 3. Sign the envelope
signed = sign_envelope(envelope, keypair)

# 4. Agent pays (dry_run=True skips HTTP — remove for live payments)
result = pay(
    signed,
    recipient="38873dbc-abfa-4ab5-be25-050496d4a0c3",
    amount=5.00,
    memo="supplier invoice #42",
    dry_run=True,
)

print(result.tx_id)    # "dry-run-no-http"
print(result.status)   # "dry_run"

Set PQSAFE_API_KEY in your environment and remove dry_run=True for live calls.

API reference

generate_keypair() -> KeyPair

Generate an ML-DSA-65 key pair. Returns a KeyPair with .public_key and .secret_key as raw bytes. Use .public_key_hex() and .secret_key_hex() for hex-encoded strings.

create_envelope(...) -> SpendEnvelope

Build a new unsigned SpendEnvelope. Parameters:

Parameter Type Description
issuer str PQSafe address (pq1 + 40 hex chars)
agent str Agent identifier (1-128 chars)
max_amount float Maximum spend allowed
currency str ISO 4217 currency code (e.g. "USD")
allowed_recipients list[str] Allowlist of recipient addresses
starts_in_seconds int Delay before activation (default 0)
ttl_seconds int Validity window in seconds (default 3600)
rail str | None Optional rail constraint

sign_envelope(envelope, keypair) -> SignedEnvelope

Sign a SpendEnvelope with the issuer's ML-DSA-65 key pair.

verify_envelope(signed, public_key=None) -> SpendEnvelope

Verify a SignedEnvelope. Raises ValueError on invalid signature or expired envelope.

pay(signed_envelope, request=None, *, recipient=None, amount=None, memo=None, api_key=None, base_url='https://api.pqsafe.xyz', dry_run=False) -> PaymentResult

Verify the envelope and POST to /v1/pay. Accepts a PaymentRequest, plain dict, or keyword args.

AP2 adapter (v0.1.1)

Convert between AP2 mandates and PQSafe SpendEnvelopes:

from pqsafe.adapters import ap2_mandate_to_spend_envelope, spend_envelope_to_ap2_mandate, IntentMandate

# IntentMandate → SpendEnvelope
mandate = IntentMandate(
    mandateId="m-001",
    merchantId="merchant-xyz",
    description="Purchase intent",
    maxAmount=100.0,
    currency="USD",
    expiresAt="2026-12-31T23:59:59Z",
    agentId="my-agent-v1",
    issuerAddress="pq1" + "a" * 40,
)
envelope = ap2_mandate_to_spend_envelope(mandate, issuer_address="pq1" + "a" * 40, ttl_seconds=3600)

# SpendEnvelope → CartMandate
cart = spend_envelope_to_ap2_mandate(envelope, "cart")

# Verify an AP2 mandate with a PQ signature
from pqsafe.adapters import verify_ap2_with_pq_wrapper
valid = verify_ap2_with_pq_wrapper(mandate, pq_sig_bytes, pq_public_key_bytes)

ACP adapter (v0.1.1)

Convert between Stripe ACP Shared Payment Tokens and SpendEnvelopes:

from pqsafe.adapters import acp_token_to_spend_envelope, spend_envelope_to_acp_token, SharedPaymentToken

spt = SharedPaymentToken(...)  # from Stripe API
envelope = acp_token_to_spend_envelope(spt, issuer_address="pq1" + "a" * 40)

# Back to SPT creation params (for POST /v1/shared_payment_tokens)
params = spend_envelope_to_acp_token(envelope, payment_method_id="pm_123")

Zero-decimal currencies (JPY, KRW, etc.) are handled automatically — no manual division by 100.

Sprint 2: Spend Policy (v0.1.1)

Three policy modes for SpendEnvelopes:

from pqsafe.sprint2 import SingleUsePolicy, PerTxCapPolicy, CumulativeCapPolicy
from pqsafe.sprint2 import validate_spend_policy, assert_policy_consistency

policy = validate_spend_policy({"mode": "per_tx_cap", "perTxLimit": 25.0})
assert_policy_consistency(policy, max_amount=100.0)  # validates perTxLimit <= maxAmount

Revocation and issuer hierarchy stubs are included (Sprint 3 implementation: May 19 – Jun 8).

Links

Cryptographic backend

The SDK uses ML-DSA-65 (NIST FIPS 204) via pqcrypto>=0.4.0. If pqcrypto cannot be installed, a classical Ed25519 fallback is used (clearly marked in the code with TODO comments). The fallback is not post-quantum secure and must not be used in production.

License

MIT

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

pqsafe_agent_pay-0.1.0.tar.gz (48.4 kB view details)

Uploaded Source

Built Distribution

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

pqsafe_agent_pay-0.1.0-py3-none-any.whl (41.5 kB view details)

Uploaded Python 3

File details

Details for the file pqsafe_agent_pay-0.1.0.tar.gz.

File metadata

  • Download URL: pqsafe_agent_pay-0.1.0.tar.gz
  • Upload date:
  • Size: 48.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for pqsafe_agent_pay-0.1.0.tar.gz
Algorithm Hash digest
SHA256 98458a7a59d5ed3538db334beb8fcc08ca11e805e46abd6da72f126eea16b401
MD5 99cb198dfe8914416d34dcd62482b89d
BLAKE2b-256 62ec0a42bcdd414b7bfe66a80ee00d1b91bb7d5412e35e9265f96463df88cc38

See more details on using hashes here.

File details

Details for the file pqsafe_agent_pay-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pqsafe_agent_pay-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 626ab12682bbdf56d5b959121f0ac2399077874bfb8229080265073d7e1e14a9
MD5 36472626e3b2556a50742b05251ff88b
BLAKE2b-256 58b660c1fd140a0ffc8a7aa16bc0a3f24a85b1dedca8893c7efc7f412d436ebe

See more details on using hashes here.

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