Skip to main content

m2m-monster (Python)

Python SDK for m2m.monster: non-custodial agent-to-agent payments over x402 v2 with the m2m-split scheme on Solana. Builds the same bytes as the TypeScript SDK.

Mainnet API: https://api.m2m.monster. Free Devnet sandbox for testing: https://sandbox.m2m.monster with Devnet keys and a Devnet RPC. The examples below use the sandbox, so copying them never spends real funds.

Agents keep their own keys; the SDK builds, simulates and signs locally. The fee (min(max(0.25% × amount, $0.001), $0.5), borne by the payee) is paid in USDC to the treasury inside the same transaction; the payer pays its own gas.

pip install m2m-monster

Pay a seller that answers 402

from solders.keypair import Keypair
from m2m_monster import ApiClient, PaymentClient, Rpc

api = ApiClient("https://sandbox.m2m.monster")
client = PaymentClient(
    Rpc("https://api.devnet.solana.com"),
    Keypair.from_base58_string(SECRET_KEY),  # stays local
    api.service_address(),
)
res = client.get("https://seller.example/resource")  # 402 -> pay -> 200

Get paid

from m2m_monster import ApiClient, DEVNET, Paywall, Rpc

paywall = Paywall(ApiClient("https://sandbox.m2m.monster"), Rpc("https://api.devnet.solana.com"), DEVNET, "YOUR_WALLET")
outcome = paywall.handle(request_headers, request_url, {"mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "amount": "100000"})
if not outcome.paid:
    return outcome.status, outcome.headers, outcome.body   # the 402
# run your handler, then add outcome.headers (PAYMENT-RESPONSE with the receipt)

Retries: never pay twice

PaymentClient keeps each payment it signs in memory, bound to the request (its Idempotency-Key header, else method, URL and body), until the outcome is known. If a call fails after paying (for example the response is lost), repeat the same call: it resends the same signed payment instead of requesting a new quote, and decides from the seller's answer and the chain.

from m2m_monster import payment_outcome

res = client.get("https://seller.example/resource")  # if it raises, repeat this same call
outcome = payment_outcome(res)  # None when no payment was needed
# outcome["status"]: "paid" | "already_paid" | "not_paid"; outcome["transaction"],
# outcome["receipt"], outcome["receipt_data"] (only when the SDK verified the receipt)
  • paid: this response settled the payment.
  • already_paid: an earlier attempt paid; the seller does not serve the resource again. The receipt is set when the seller returned it and the SDK verified it on-chain (service signature, confirmed transaction, this payment's signature); otherwise the transaction is confirmed on-chain.
  • not_paid: proven not settled (failed on-chain, or not found after its blockhash expired). The next call pays again with a new quote.
  • Error PAYMENT_STATUS_UNKNOWN (M2mError): the outcome could not be determined (RPC unavailable, or the transaction not found while its blockhash is still valid, about a minute or two after signing). The SDK keeps the payment and does not pay again for that request; repeat the same call later.

Concurrent calls for the same request share one attempt and never sign twice.

Pending payments live in memory only. After a process restart the SDK does not know a payment signed before the restart: repeating the request gets a new quote and signs a new payment. Before paying again after a restart, check the chain: list your payer address's recent transactions (getSignaturesForAddress) and look for an m2m-split payment to that payee (memo settled via m2m.monster <quote id>) since before the restart.

Without the SDK

A signed payment is valid once and unlocks the resource once. If you send the same PAYMENT-SIGNATURE again, nothing is paid or served again. The seller answers 402 with:

  • body {"error":{"code":"QUOTE_EXPIRED","message":"This payment was already used."}}
  • header PAYMENT-RESPONSE (base64 JSON): success: false, errorReason: "QUOTE_EXPIRED", transaction = the Solana signature of your original payment, payer, and extensions["m2m-receipt"].info.receipt = the original signed receipt.

QUOTE_EXPIRED with a transaction and a receipt is proof that you already paid: verify the receipt (POST /v1/receipts/verify with {"receipt": "<jws>"}, or verify_receipt over MCP) and do not pay again. QUOTE_EXPIRED without them proves nothing: before paying again, check on-chain whether the transaction you signed landed (getSignatureStatuses with searchTransactionHistory) and wait until its blockhash has expired.

Docs: https://m2m.monster/llms.txt · Errors: https://api.m2m.monster/v1/errors · Devnet sandbox docs: https://sandbox.m2m.monster/llms.txt

License: Apache-2.0

Metadata

Release files for m2m-monster 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for m2m-monster 1.1.0
File Size Uploaded Provenance
m2m_monster-1.1.0.tar.gz 39.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for m2m-monster 1.1.0
File Interpreter ABI Platform
m2m_monster-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 122.5 kB

Release files / m2m_monster-1.1.0.tar.gz

Download URL m2m_monster-1.1.0.tar.gz
Size 39.4 kB
Tags Source
SHA-256 checksum
How to use checksums
2f4b9f2205f0b0293dccb22403883f4cdc21f1ca186fa340d3019ca838714a8b
BLAKE2b-256 checksum
How to use checksums
343a8408440ff5fe22006656a2233a737b8dad14406d308a04ea6de7e61046f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / m2m_monster-1.1.0-py3-none-any.whl

Download URL m2m_monster-1.1.0-py3-none-any.whl
Size 83.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6001cfd4b9b477db0fe1ce781f9349b0b02f7e474dfa8f0ee4978f8f183ce478
BLAKE2b-256 checksum
How to use checksums
e604e35df2e5362f80386d4833c71ede7cf60b626ec10ab76d4e21be479ea720
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for m2m-monster 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page