transfer that settles on-chain individually — no channel setup, no pre-funding, and no external facilitator required. This is the simplest way to get started with MPP on Stellar.
How charge payments work
signedHash credential — the transaction hash plus a signature proving control of the from account — for server verification.
This tutorial walks through building a payment-gated API with Node.js and Express using @stellar/mpp.
To follow this guide, you will need Node.js installed locally. Recommend using the latest LTS version.
Create a project
Create a new folder for the tutorial and initialize a Node.js project:type=module setting lets you use ES module import syntax in the examples below.
Install the npm packages used by the server and client:
Create server.js
Create a file named server.js and paste in the following code:
server.js
STELLAR_RECIPIENT to the Stellar public key (G...) for the account that should receive USDC payments. Your account will need a testnet USDC trustline — see Setting up a testnet wallet below.
Start the API locally:
402 Payment Required, including headers that describe the payment requirements. A compliant client builds a signed Soroban SAC transfer and retries the request — no external facilitator needed. The server verifies and broadcasts the transaction directly.
Create client.js
Setting up a testnet wallet
Create a fresh account and fund it with testnet XLM and testnet USDC using Stellar Lab:- Create a new keypair: https://lab.stellar.org/account/create
- Fund with testnet XLM (Friendbot): https://lab.stellar.org/account/fund
- Create the USDC trustline (there’s a button on the fund page above)
- Get testnet USDC from the Circle faucet — select Stellar Testnet and paste in your public key: https://faucet.circle.com
.env file and add your testnet secret key:
.env
Client code
With your server running, create a file namedclient.js and paste in the following code:
client.js
Run the client
Once the account is funded and the secret key is in.env, run the client in a second terminal:
- Makes a
GET /my-servicerequest - Receives a
402 Payment Requiredwith payment details in the response headers - Builds and signs a Soroban SAC
transferon Stellar Testnet - Retries the request with the signed credential
- Receives
200 OKwith the protected content:{ secret: 'valuable content' }
STELLAR_RECIPIENT wallet. No facilitator, no extra infrastructure.
Push mode
The examples above use pull mode (default), where the server broadcasts the signed transaction. In push mode, the client broadcasts the transaction directly and sends a signed hash credential (signedHash) to the server for verification.
Push mode client
To use push mode, setmode: "push" in the client configuration and provide the keypair of the from account (the account funding the transfer). The SDK handles signedHash credential generation automatically — no manual signing code required:
client.js (push mode)
Push mode server
The server accepts both pull and push credentials automatically — no extra configuration needed. The only change from the pull mode server is movingstore into stellar.charge():
server.js (push mode)
Signed hash credentials
The SDK generatessignedHash credentials automatically when mode: "push" is set — you do not write any signing code. Under the hood, the client:
- Computes a hash of the transaction envelope
- Creates the string
"{challenge.id}:{hash}"wherechallenge.idis the MPP challenge identifier - Signs this string using the keypair of the
fromaccount
from account — the account funding the transfer — ensuring the client authorized the specific hash. With sponsored fees the transaction envelope is sourced by the fee payer, so the signature is always checked against the from account rather than whoever broadcasts.
Sponsored fees (optional)
By default, the client pays Stellar network fees. To have the server pay fees on behalf of the client, configure afeePayer on the server:
FEE_PAYER_SECRET before running the server if you use sponsored fees.
When feePayer is configured, the server automatically signals fee sponsorship to the client via the challenge. The client then signs only the Soroban auth entries (not the full transaction envelope). The server rebuilds the transaction with the envelopeSigner’s account as source and broadcasts it. Optionally, add feeBumpSigner inside feePayer to wrap the transaction in a fee bump.
Channel open removalThe channel
open MPP action was removed in v0.7 as it was dead code — the Soroban contract has no on-chain open entrypoint. Channels are created on-chain directly by signing and broadcasting a deploy transaction. See the MPP Session Guide for channel setup details.Learn more
- @stellar/mpp on GitHub — Full API reference, channel mode, and examples
- @stellar/mpp (npm) — npm package for MPP on Stellar
- MPP Specification — Official MPP protocol specification and whitepaper
- mppx (npm) — Core MPP framework library used by both server and client
- Signing Soroban invocations — Auth-entry signing on Stellar
- one-way-channel contract — Soroban contract powering the channel payment mode
- MPP Session Guide — Set up off-chain payment channels for high-frequency payments