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.monsterwith 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, andextensions["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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| m2m_monster-1.1.0.tar.gz | 39.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.