Skip to main content

mpp-accept-payments

Example merchant server — clone and run locally in minutes.
This runs an example merchant server that gates a route behind an MPP payment — the same pattern you’d use to charge an AI agent for calling an API endpoint or an MCP tool, not just a human-facing page. Unlike x402, MPP has no facilitator: the server verifies the credential in-process and settles it through the Atum payment gateway.

Prerequisites

npm is included with Node.js.
Verify:

Prerequisites for real settlement

The stub needs no funds. When you settle for real, the merchant is a pure recipient — it holds no keys and moves no funds, so it only needs a valid receive address on the destination chain — see Prerequisites.

1. Clone and install

2. Configure

The defaults run against a stubbed settlement out of the box — no changes needed to run locally. To test with a real testnet settlement, set USE_STUB_SUBMITTER=false and point GATEWAY_URL at an Atum Payment Gateway. The corridor’s contract addresses are then resolved automatically from the gateway, so you never set them in .env (see Choose an environment).

3. Start the server

You should see:
The stub submitter returns a canned settlement confirmation, so the full 402 → pay → 200 flow runs with no gateway and no on-chain funds. Once running, the merchant is ready to receive requests — from a human’s browser, a script, or an AI agent’s tool call.

4. Test the flow

Drive a payment through it with the mpp-make-payments client — a plain curl can’t easily produce the signed credential MPP expects. With this server running, in the client example:
The client requests GET /paid, receives the 402 challenge (in a WWW-Authenticate: Payment header), signs a credential, retries with Authorization: Payment, and receives:
The Payment-Receipt header on the 200 carries the settlement confirmation.

What’s happening

Looking at src/merchant.ts:
  1. A request arrives at GET /paid.
  2. If no credential is present → mppx returns 402 with the atum-escrow challenge (the corridor terms).
  3. If an Authorization: Payment credential is present → the atum-escrow method’s verify() checks the signature and terms in-process.
  4. verify() hands the payment to your PaymentSubmitter, which settles it — the stub returns a canned confirmation; a real submitter posts to Atum’s Payment Gateway.
  5. On success → 200 with the protected content and a Payment-Receipt header.
The merchant holds no keys and runs no facilitator. The PaymentSubmitter is the one seam where settlement happens — and the same code path serves a human, a script, or an agent.

Going to testnet

Settling for real means switching off the stub submitter, setting your corridor and receive address, and pointing GATEWAY_URL at an Atum Payment Gateway — the settlement vault, role, proxy, and verifier addresses are then resolved from the gateway automatically, so you don’t configure them by hand. See the example README for .env values and a real settlement log — its Going to testnet / mainnet section walks through that app. New to Atum’s environments? See Choose an environment for which one to target and what to expect from production-testnet. Run through the pre-flight checklist before your first real payment.

Next steps