Net Payments SDK (x402-native)
net-payments is not a payment processor. It does not custody funds,
process payments, issue invoices, determine taxes, or clear transactions.
x402 v2 moves the money; Net signs the commercial facts around it —
provider identity, discovery-time pricing, tiered verification, immutable
billing, and spend policy.
Before you write or edit any payment code, read concepts.md in this skill
directory. It is the conceptual prerequisite for everything else. The API
templates will look like a dozen payment SDKs and you will write something that
compiles, runs, and is a rejected PR — because the constraints here
(non-custodial, byte-preserved x402, no parallel wire format, tiers not
booleans) are not the constraints of a normal payments library.
How to use this skill
Load reference files on demand — do not read them all up front.
| File | Read when |
|---|---|
concepts.md |
Always first. The mental model, the category line, the eight doctrines, the object model at a glance, the data boundary (what "commercial facts" may and may not carry — no PII, by construction), "no HTTP endpoint required," the review invariant. ~5 min. |
bindings/coverage.md |
Before promising payments works in a given language. Payments is a three-binding subsystem: Rust, Node and Python only, and Node/Python reach it solely through the low-level package. Go and C have no payments API at all. |
object-model.md |
When touching the five Net envelopes — exact fields, the canonical signing regime, versioning, idempotency, amounts. |
x402.md |
When touching x402 structures — X402Carry byte-preservation, PaymentRequirements/PaymentPayload/settlement views, CAIP ids, the exact EVM scheme. |
provider.md |
When the user charges for a capability — PaymentEngine lifecycle (quote → verify → settle → serve → bill), provider admission policy, pricing at publish, serve_payments over the mesh, and terminal-record compaction (default-on at 6h; why status() is not an audit surface). |
caller.md |
When the user pays to invoke — CallerPaymentFlow, ProviderChannel (InProcessProvider / MeshPaymentChannel), spend check, the approval loop, the MCP gateway path. |
a2a.md |
When the user charges for an agent task — paid A2A from the money side: pricing <node>/net.a2a.task/<service>, one PaymentEngine behind both serve_payments and EngineTaskAdmissionGate, redeem_for_task against the reservation-bound input_hash, A2aCallerFlow over a durable A2aPurchaseStore, the purchase-state table (unknown vs denied{funds_ambiguous} vs paid_unexecutable), and the operator queue that accumulates by design. |
facilitator.md |
When wiring the verify/settle boundary — the Facilitator trait, the mock + its injectable modes, the real HttpFacilitator, GET /supported validation, auth, config packs. |
verification.md |
When the question is about confidence — the observed / confirmed(n) / final tiers, the independent ChainChecker, reorg freeze, the immutable chain, idempotency/replay, and the deadline on re-verification (the retention horizon). |
signer.md |
When touching settlement signing — the SchemeSigner seam, ExternalSigner (production) vs DevLocalSigner (testnet), EIP-3009 authoring, the no-raw-signing invariant. |
spend-policy.md |
When the user wants limits, budgets, or approvals — SpendPolicyEngine, SpendLimits, the fail-closed default posture, the operator approval surface, delegation inheritance. |
networks.md |
When enabling a network — CAIP-2/CAIP-19, the signed asset registry, the Base Sepolia → Base → Solana → xrpl ladder, "config, not code," the live testnet runbook. |
billing.md |
When the user wants usage records / a billing stream — BillingLog (subscribe/read/export), immutability, the lifecycle-hooks doctrine, what billing is NOT. |
http402.md |
When a Net agent pays an external x402 HTTP API — the outbound X402HttpFlow + the Python / Node PaymentHttpClient, the header-only v2 transport, why it's the same objects (the two-way door). |
failure-schematic.md |
When handling denials / refusals — the net.payment.failure@1 object that rides beside the human error, the reason→recovery mapping, the header discipline, its payment-only scope (code: "payment"; non-payment admission failures don't ride it), and how each surface (MCP / Python failure field / tracing) projects it. |
bindings.md |
First, when any code is going to be written. The routing page: which companion to load, and the two facts that decide whether there is code to write at all — payments is Rust/Python/Node only, and in Node and Python it lives in the low-level package (@net-mesh/core, net), never the wrapper. Then load exactly one of bindings/{rust,typescript,python,go,c}.md. |
testing.md |
When writing/running tests — cross-language golden vectors, the mock conformance suite, the key-invariant negative test, feature-gated suites, the env-gated live run. |
gotchas.md |
When the user's framing carries a wrong mental model, when migrating, or before merging — the review invariant, "what not to build," the byte-preservation trap, common mistakes. |
source-access.md |
When you need to read the payments source and you are not inside the Net repository. Two cases: opening a file this skill cites, and answering something this skill does not cover — the exact serialized shape of an object, how verification or settlement actually proceeds, whether a surface exists in the binding being written. One opensrc command fetches the whole tree; the page carries the root map that makes shorthand citations (core/quote.rs, x402/mod.rs) resolvable, why crates:net-payments returns "not found" (the crate is unpublished — that is not a missing feature), what the checkout will not contain, why a line anchor is a hint rather than an address, and where the golden vectors and conformance tests are. Read concepts.md for the model first; source settles mechanism, not what may be built. |
TL;DR mental model (the absolute minimum)
If you remember nothing else from concepts.md, remember these:
- x402 is the payment wire; Net signs around it. Net envelopes wrap x402 structures; they never replace, translate, or re-encode them. Chain specifics live in x402 schemes + facilitator config — never in Net core.
- Byte-preservation is law. x402 documents are carried as base64 of their
original bytes (
X402Carry), never re-serialized through Net types. Re-serializing a received x402 doc (envelope drift) is a rejected PR. - Non-custodial by construction. Identity keys ≠ settlement keys. The
SchemeSignertakes typed operations and returns signatures; there is no raw-bytes signing method and no way for a binding or agent to reach a key. - Verification is a tier, not a boolean:
observed | confirmed(n) | final. A facilitator receipt isobserved, full stop —confirmed(n)andfinalcome only from the independent on-chainChainChecker, so the facilitator is never in the trust root. Reorg is a first-class outcome that freezes the quote; billing events are immutable. - The policy engine decides, not the model. Spend policy runs caller-side before anything leaves; provider policy runs at quote issuance and re-checks before the handler. Handlers never see unpaid calls. Approvals render in UX; the decision lives in shared policy state.
- Enabling a network is config, not code. Facilitator pack + registry
entries + a conformance run — no new envelope types, no core changes, no
per-network branches outside
src/x402/. - The engine store is bookkeeping; the billing log is the record. Terminal
quote records are compacted 6h past quote expiry by default, so
engine.status()returnsNonefor a payment that completed fine — build reconciliation on the billing stream. Replay protection is never compacted: settlement-transaction tombstones are permanent at every setting, and nothing unredeemed or frozen is retired. The horizon is also your re-verification window; if you re-verify out of band, widen it or passNone.
The category line, verbatim: Net standardizes the commercial facts around capability invocation; it does not intermediate the money.
If the user's language conflicts with any of these ("Net wallet", "generate an
invoice", "sign these bytes", "translate x402", "the facilitator confirmed
finality", "auto-refund the overpayment"), stop and read gotchas.md — they're
carrying a mental model that produces compiling-but-rejected code.
Workflow when integrating
- Select the binding, then load exactly one — and answer "is there a payments
API at all" before anything else. Payments is a three-binding subsystem.
- Read the language off the project:
Cargo.toml→ Rust,package.json→ Node/TS,pyproject.tomlorrequirements.txt→ Python,go.mod→ Go,Makefile/CMakeLists.txtbeside.c/.h→ C. - Rust, Python and Node/TS have a full native demand + supply flow. Go and C have no payments API at all — not partial, not reduced. Go has a golden-vector conformance test and nothing else; C does not even have that. If the task is "add x402 payments to our Go service", that is a language choice or a feature request, not a coding task. Say so first.
- Then read
bindings.md(routing) and exactly one companion —bindings/rust.md,bindings/typescript.md,bindings/python.md,bindings/go.md,bindings/c.md.bindings/coverage.mdis the per-operation matrix and the authoritative answer to "does this language have X". - Payments is not in the ergonomic wrapper. Neither
@net-mesh/sdknornet_sdkcontains a line of it. Every payments symbol in Node and Python is in@net-mesh/coreandnetrespectively, and there is no@net-mesh/paymentspackage. An import from the wrapper fails in a way that looks like a missing feature. - Never default to Rust because the substrate is Rust. With no project context and no language named, ask — the answer decides whether there is any code to write.
- Read the language off the project:
- Read
concepts.mdif this is your first invocation this session. - Which side is the user on?
- Charging for a capability (provider) →
provider.md. Price at publish (net.pricing.terms@1), run thePaymentEnginelifecycle, pass aPaymentFlowintogated_invokeso the payment gate runs before the handler. - Paying to invoke (caller) →
caller.md.CallerPaymentFlowover aProviderChannel, spend policy, the approval loop; branch on thenet.payment.failure@1schematic that rides a denial (failure-schematic.md). - Paying an external x402 HTTP API →
http402.md(X402HttpFlow/PaymentHttpClient). - Charging for, or buying, an agent task →
a2a.md. Paid A2A is prepare → purchase → submit, not a one-shot invoke: the same engine must sit behindserve_paymentsand the admission gate, and the caller's attempt is durable on disk. Rust and Python only, both directions.
- Charging for a capability (provider) →
- Pick the facilitator. Default to
MockFacilitator(the conformance backbone) for anything not touching real money;HttpFacilitator+ a config pack for a real network.facilitator.md. - Set the required tier. Receipt-trust (
observed) or an independent check (confirmed(n)/finalviaChainChecker)?verification.md. - Wire the signer if settling on a real network —
ExternalSigner(eip155/EIP-3009; key never in Net),ExternalSvmSigner(solana/SPL, intent-in/blob-out), orExternalXrplSigner(xrpl/presigned Payment blob), registered per namespace;DevLocalSignerfor testnet only (behindunsafe-dev-signer). From Python, all three ride thepayment_signer*kwargs.signer.md. - Configure spend policy — limits, allowed networks/assets, the approval
surface. Real networks deny by default.
spend-policy.md. - Enabling a new network? It's config + registry + conformance, never
code.
networks.md. - Surface billing via
BillingLog(stream/export).billing.md. - Test against golden vectors + the mock conformance suite; keep the
key-invariant negative test green.
testing.md. - Before merging, run the change past the review invariant in
gotchas.md— most payments mistakes are scope violations, not bugs. - If you're unsure about an API, read the source — it's ground truth:
- Rust core:
net/crates/net/payments/src/(engine/,flow/,facilitator/,core/,x402/,policy/,checker/,billing/) - Failure schematic (SDK wire object):
net/crates/net/sdk/src/tool_payment.rs - Rust examples/tests:
payments/examples/,payments/tests/ - Python surface:
net/crates/net/bindings/python/src/capability_gateway.rs,payment_http.rs, and the_net.pyistub - Cross-lang vectors:
net/crates/net/tests/cross_lang_payments/
- Rust core:
What this skill deliberately does not cover
- The base mesh, nRPC, capabilities, MCP bridge, event bus — that's the
net-event-busskill. This skill assumes the substrate and only covers the money layer on top. - Refund/dispute semantics — the
net.payment.dispute@1tag is reserved; no semantics ship today. - RFQ / dynamic pricing — waits on x402 v2 dynamic-pricing maturity; no parallel dynamic flow, no counter-offer object (that absence is the rule).
- Accounts / postpaid / prepaid — bilateral, provider-scoped, and not shipped; company-held credits only via licensed partners.
- Inbound HTTP 402 serving — deferred, demand-driven.
If the user asks about these, say where they stand rather than inventing an API.