# MPP-QuickStart
Richten Sie einen Server ein, der Zahlungen per Kryptowährung oder Fiat-Währung akzeptiert.
## MPP-Zahlungs-Endpoint-Generator
Erfahren Sie, wie Sie mit dem Machine Payments Protocol (MPP) einen Server erstellen und bereitstellen, der Zahlungen sowohl mit Krypto als auch mit gemeinsam genutzten Zahlungstoken (Shared Payment Token, SPT) akzeptiert.
### Stripe Node-Bibliothek installieren
Installieren Sie das Paket und importieren Sie es in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine package.json-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
#### npm
Bibliothek installieren:
```bash
npm install --save stripe
```
#### GitHub
Oder laden Sie den Quellcode der Stripe-Node-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-node) herunter.
### Stripe-Ruby-Bibliothek installieren
Installieren Sie Stripe Ruby Gem und fordern Sie es in Ihrem Code an. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine Gemfile benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
#### Terminal
Gem installieren:
```bash
gem install stripe
```
#### Bundler
Fügen Sie diese Zeile in Ihre Gemfile ein:
```bash
gem 'stripe'
```
#### GitHub
Oder laden Sie den Quellcode von Stripe Ruby Gem direkt von [GitHub](https://github.com/stripe/stripe-ruby) herunter.
### Stripe Java-Bibliothek installieren
Fügen Sie Ihrem Build die Abhängigkeit hinzu und importieren Sie die Bibliothek. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine pom.xml-Beispieldatei (für Maven) benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
#### Maven
Fügen Sie folgende Abhängigkeit zu Ihrer POM-Datei hinzu und ersetzen Sie {VERSION} durch die Versionsnummer, die Sie verwenden möchten.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Fügen Sie die Abhängigkeit zu Ihrer build.gradle-Datei hinzu und ersetzen Sie {VERSION} durch die Versionsnummer, die Sie verwenden möchten.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Laden Sie die JAR-Datei direkt von [GitHub](https://github.com/stripe/stripe-java/releases/latest) herunter.
### Stripe-Python-Paket installieren
Installieren Sie das Stripe-Paket und importieren Sie es in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine requirements.txt-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
#### pip
Installieren Sie das Paket über pip:
```bash
pip3 install stripe
```
#### GitHub
Laden Sie den Quellcode der Stripe-Python-Bibliothek direkt [von GitHub](https://github.com/stripe/stripe-python) herunter.
### Stripe PHP-Bibliothek installieren
Installieren Sie die Bibliothek mit Composer und initialisieren Sie sie mit Ihrem geheimen API-Schlüssel. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine composer.csproj-Datei benötigen, laden Sie die Dateien über den Download-Link im Code-Editor herunter.
#### Composer
Bibliothek installieren:
```bash
composer require stripe/stripe-php
```
#### GitHub
Oder laden Sie den Quellcode der Stripe-PHP-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-php) herunter.
### Server einrichten
Fügen Sie Ihrem Build die Abhängigkeit hinzu und importieren Sie die Bibliothek. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine go.mod-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
#### Go
Nutzen Sie für die Initialisierung Go-Module:
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Oder laden Sie den Quellcode des Stripe-Go-Moduls direkt von [GitHub](https://github.com/stripe/stripe-go) herunter.
### Stripe.net-Bibliothek installieren
Installieren Sie das Paket mit .NET oder NuGet. Wenn Sie aber von Grund auf neu beginnen möchten, laden Sie die Dateien herunter, die eine konfigurierte .csproj-Datei enthalten.
#### dotnet
Bibliothek installieren:
```bash
dotnet add package Stripe.net
```
#### NuGet
Bibliothek installieren:
```bash
Install-Package Stripe.net
```
#### GitHub
Oder laden Sie den Quellcode der Stripe.net-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-dotnet) herunter.
### Stripe-Bibliotheken installieren
Installieren Sie die Pakete und importieren Sie sie in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine `package.json`-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.
Bibliotheken installieren:
```bash
npm install --save stripe @stripe/stripe-js next
```
### Stripe initialisieren
Richten Sie den Stripe Client mit Ihrem Geheimschlüssel ein und setzen Sie die API-Version auf `2026-03-04.preview`. Der Client verarbeitet Zahlungen sowohl für Kryptowährungen als auch für SPT-Zahlungsmethoden.
Stellen Sie sicher, dass [Krypto-Einzahlungen](https://support.stripe.com/questions/get-started-with-pay-with-crypto) für Ihr Stripe-Konto aktiviert sind.
### PaymentIntent-Handler erstellen
Erstellen Sie eine Funktion, die festlegt, wohin Krypto-Zahlungen gesendet werden sollen. Extrahieren Sie entweder die Adresse aus einem bestehenden Zahlungsheader für Wiederholungsversuche oder zur Überprüfung oder erstellen Sie einen neuen [PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md), um eine neue Einzahlungsadresse zu generieren.
Wenn Sie ein [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) mit `crypto` als *Zahlungsmethode* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) und dem `deposit`-Modus erstellen, geben Sie die Netzwerke an, die Sie unterstützen möchten, indem Sie `deposit_options` verwenden. Stripe gibt die Einzahlungsadressen für die angeforderten Netzwerke zurück. Die Funktion extrahiert die Adresse des Tempo-Netzwerks, die Kundinnen und Kunden zum Senden von *Stablecoins* (A cryptocurrency that's pegged to the value of a fiat currency or other asset in order to limit volatility) verwenden.
### Erstellen Sie einen serverseitigen Zahlungshandler (SPTs)
Richten Sie mithilfe von [Mppx.create](https://mpp.dev/sdk/typescript/server/Mppx.create) einen serverseitigen Zahlungshandler für SPTs ein. Konfigurieren Sie diesen so, dass er Kartenzahlungen und Zahlungen über Link mithilfe der Stripe-Zahlungsabwicklung akzeptiert.
### Erstellen Sie die Hono-App
Starten Sie den Hono-Server, auf dem beide Zahlungs-Endpoints gehostet werden.
### FastAPI-App erstellen
Initialisieren Sie den FastAPI-Server, auf dem der Zahlungs-Endpoint gehostet wird.
### Erstellen Sie den SPT-Testhelfer
Fügen Sie einen `POST`-Endpoint hinzu, um SPTs für Tests zu erstellen.
In der Produktion würde das Backend des aufrufenden Clients SPTs ausgeben, nicht Ihr geschützter Endpoint.
### Erstellen Sie einen Endpoint für Krypto-Zahlungen
Definieren Sie den Endpoint `/crypto/paid`, der Krypto-Zahlungen akzeptiert.
- Erstellen Sie mithilfe von [Mppx.create](https://mpp.dev/sdk/typescript/server/Mppx.create) einen serverseitigen Zahlungshandler für Tempo.
- Gibt eine `402-Antwort (Zahlung erforderlich)` mit Zahlungsdetails zurück, wenn die Anfrage keine gültige Zahlung enthält.
- Überprüft bei jeder Anfrage die Zahlungsanfragen
- Gewähren Sie Zugriff, wenn die Anfrage gültige Zahlungsdaten enthält.
### Erstellen Sie einen Endpoint für Krypto-Zahlungen
Definieren Sie den Endpoint `/paid`, der Krypto-Zahlungen auf Tempo akzeptiert.
- Erstellen Sie mithilfe von [Mpp.create](https://mpp.dev/sdk/python/server/Mpp.create) einen serverseitigen Zahlungshandler für Tempo.
- Prüfen Sie jede Anfrage auf gültige Zahlungsdaten.
- Wenn die Anfrage keine gültigen Zahlungsdaten enthält, geben Sie eine Antwort `402 Payment Required` mit den Angaben zur Zahlung vom Tempo-Handler zurück.
- Wenn die Anfrage eine Zahlungsanfrage enthält, verifizieren Sie sie mit dem Tempo-Handler.
- Erlauben Sie den Zugriff erst, wenn die Zahlungsdaten oder die Zahlungsanfrage gültig sind.
### Erstellen Sie einen SPT-Zahlungs-Endpoint
Definieren Sie den Endpoint `/spt/paid`, der SPT-Zahlungen akzeptiert.
- Gibt eine `402-Antwort (Zahlung erforderlich)` mit Zahlungsdetails zurück, wenn die Anfrage keine gültige Zahlung enthält.
- Überprüft bei jeder Anfrage die Zahlungsanfragen
- Gewähren Sie Zugriff, wenn die Anfrage gültige Zahlungsdaten enthält.
### Konfigurieren Sie die Zahlungsmethode
Richten Sie die clientseitige Zahlungsmethode zum Erstellen von SPTs ein. Die Funktion `createToken` ruft den Endpoint `/create-spt` Ihres Backends auf, um Shared Payment Tokens zu generieren.
### Zahlungsanfragen erhalten
Rufen Sie die `402`-Anfrage vom geschützten Endpoint ab, um die Anforderungen an die Zahlung zu verstehen.
### Eine Zahlung angeben
Geben Sie die zu verwendende Zahlung an. In diesem Beispiel verwendet der Code eine Zahlung per Testkarte.
### Erstellen Sie Zahlungsdaten
Verwenden Sie die Zahlungsmethode, um anhand der Anforderung und der Zahlungsmethode Zahlungsdaten zu erstellen.
### Mit Zahlungsdaten erneut versuchen
Stellen Sie eine weitere Anfrage an den geschützten Endpoint mit den Zahlungsdaten im Header `Authorization`.
### Server ausführen
Erstellen und starten Sie Ihren Server, um beide Endpoints zu testen.
```bash
npm run dev
```
### Server ausführen
Erstellen und führen Sie Ihren Server aus, um den Endpoint auf `http://localhost:4242/paid`. zu testen
```bash
uv run python main.py
```
### Test ohne Zahlung
Stellen Sie eine Anfrage an den Krypto-Endpoint ohne Zahlung, um zu bestätigen, dass er einen `402`-Statuscode mit Zahlungsdetails zurückgibt.
```bash
curl http://localhost:4242/crypto/paid
```
Sie erhalten eine `402 Payment Required`-Antwort mit Informationen zur Zahlung des Machine Payment Protocol (MPP).
### Test ohne Zahlung
Stellen Sie eine Anfrage an den Endpoint ohne Zahlung, um zu überprüfen, dass er einen `402`-Statuscode mit Zahlungsdetails zurückgibt.
```bash
curl http://localhost:4242/paid
```
Sie erhalten eine `402 Payment Required`-Antwort mit Informationen zur Zahlung des Machine Payment Protocol (MPP).
### Testen Sie Krypto-Zahlungen
Verwenden Sie das [mppx](https://www.npmjs.com/package/mppx)-Tool von Tempo, um den Ablauf der Krypto-Zahlung zu testen. Das Tool verarbeitet MPP und schließt die Zahlung automatisch ab.
```bash
mppx http://localhost:4242/crypto/paid
```
Mit den Befehlen `mppx account create` und `mppx account fund` können Sie eine Test-Wallet erstellen und mit Guthaben aufladen. Nach erfolgreicher Zahlung gibt der Server den Inhalt zurück. Sie können die Zahlung im [Stripe-Dashboard](https://dashboard.stripe.com) unter **Zahlungen** bestätigen.
### Testen Sie Krypto-Zahlungen
Verwenden Sie das [mppx](https://www.npmjs.com/package/mppx)-Tool von Tempo, um den Ablauf der Krypto-Zahlung zu testen. Das Tool verarbeitet MPP und schließt die Zahlung automatisch ab.
```bash
mppx http://localhost:4242/paid
```
Mit den Befehlen `mppx account create` und `mppx account fund` können Sie ein Test-Wallet erstellen und mit Guthaben aufladen. Nach einer erfolgreichen Zahlung gibt der Server den Inhalt zurück. Sie können die Zahlung im [Stripe-Dashboard](https://dashboard.stripe.com) unter **Zahlungen** bestätigen.
### Testen Sie SPT-Zahlungen
Verwenden Sie für SPT-Zahlungen das enthaltene Script `client.ts`, das den gesamten Zahlungsablauf mit SPTs veranschaulicht.
```bash
npx tsx client.ts
```
Das Client-Script:
1. Ruft die `402`-Anfrage von `/spt/paid` ab
1. Erstellt eine SPT mit dem Helper-Endpoint `/create-spt`
1. Erstellt Zahlungsdaten
1. Ruft die Anfrage mit den Zahlungsdaten für den Zugriff auf die geschützte Ressource ab
Sie können die Zahlung im [Stripe-Dashboard](https://dashboard.stripe.com) unter **Payments** bestätigen.
- Node.js 20+
- npm or pnpm package manager
- Stripe account with crypto payments enabled
- Python 3.12+
- [uv](https://github.com/astral-sh/uv) package manager
- Stripe account with crypto payments enabled
1. Install dependencies
~~~
npm install
~~~
2. Configure environment variables
~~~
cp .env.template .env
\# Edit .env with your credentials
~~~
3. Run the server
~~~
npm run dev
~~~
1. Install dependencies
~~~
uv sync
~~~
2. Configure environment variables
~~~
cp .env.template .env
\# Edit .env with your credentials
~~~
3. Run the server
~~~
uv run python main.py
~~~
The server provides two endpoints:
- `/crypto/paid`: - Accepts crypto payments on Tempo
- `/spt/paid`: - Accepts shared payment tokens (SPTs) payments (cards and Link)
The server provides one endpoint:
- `/paid`: - Accepts crypto payments on Tempo
Make a request without payment to see the `402` response:
~~~
curl http://localhost:4242/crypto/paid
curl http://localhost:4242/spt/paid
~~~
Make a request without payment to see the `402` response:
~~~
curl http://localhost:4242/paid
~~~
[mppx](https://www.npmjs.com/package/mppx) is a command-line tool for testing crypto MPP endpoints:
~~~
npx mppx http://localhost:4242/crypto/paid
~~~
You can create and fund a test wallet with:
~~~
npx mppx account create
npx mppx account fund
~~~
[mppx](https://www.npmjs.com/package/mppx) is a command-line tool for testing crypto MPP endpoints:
~~~
npx mppx http://localhost:4242/paid
~~~
You can create and fund a test wallet with:
~~~
npx mppx account create
npx mppx account fund
~~~
import stripe
\# Stripe handles payment processing and provides the crypto deposit address.
STRIPE_SECRET_KEY = os.getenv("STRIPE_SECRET_KEY")
if not STRIPE_SECRET_KEY:
raise ValueError("STRIPE_SECRET_KEY environment variable is required")
stripe.api_key = STRIPE_SECRET_KEY
stripe.api_version = "2026-03-04.preview"
stripe.set_app_info(
"stripe-samples/machine-payments",
url="https://github.com/stripe-samples/machine-payments",
version="1.0.0",
)
# Secret used to secure payment challenges.
# https://mpp.dev/protocol/challenges#challenge-binding
mpp_secret_key = os.urandom(32).hex()
\# In-memory cache for deposit addresses (TTL: 5 minutes, max 1024 entries)
# NOTE: For production, use a distributed cache like Redis instead of cachetools
payment_cache: TTLCache[str, bool] = TTLCache(maxsize=1024, ttl=300)
def _extract_recipient_from_authorization(authorization: str | None) -> str | None:
if not authorization or not authorization.startswith("Payment "):
return None
credential = Credential.from_authorization(authorization)
request = _b64_decode(credential.challenge.request)
to_address = request.get("recipient")
if to_address and isinstance(to_address, str):
normalized = to_address.lower()
if normalized not in payment_cache:
raise ValueError("Invalid payTo address: not found in server cache")
return normalized
raise ValueError("PaymentIntent did not return expected crypto deposit details")
async def create_pay_to_address(request: Request) -> str:
"""
This function determines where payments should be sent. It either:
1. Extracts the address from an existing payment header (for retry/verification), or
2. Creates a new Stripe PaymentIntent to generate a fresh deposit address.
"""
recipient = _extract_recipient_from_authorization(
request.headers.get("authorization")
)
if recipient:
return recipient
# Create a new PaymentIntent to get a fresh crypto deposit address.
decimals = 6 # USDC has 6 decimals
amount_in_cents = int(10000 / (10 ** (decimals - 2)))
payment_intent = stripe.PaymentIntent.create(
amount=amount_in_cents,
currency="usd",
payment_method_types=["crypto"],
payment_method_data={"type": "crypto"},
payment_method_options=cast(
Any,
{
"crypto": {
"mode": "deposit",
"deposit_options": {"networks": ["tempo"]},
}
},
),
confirm=True,
)
next_action = payment_intent.get("next_action", {})
deposit_details = next_action.get("crypto_display_details", {})
if not deposit_details:
raise ValueError("PaymentIntent did not return expected crypto deposit details")
deposit_addresses = deposit_details.get("deposit_addresses", {})
tempo_address = deposit_addresses.get("tempo", {})
pay_to_address = tempo_address.get("address")
if not pay_to_address:
raise ValueError("PaymentIntent did not return expected crypto deposit details")
print(
f"Created PaymentIntent {payment_intent['id']} "
f"for ${amount_in_cents / 100:.2f} -> {pay_to_address}"
)
normalized = pay_to_address.lower()
payment_cache[normalized] = True
return normalized
\# Tempo token address for USD stablecoin
PATH_USD = "0x" + "20c" + "0" * 37
app = FastAPI(title="MPP REST API")
\# GET /paid - Accept crypto payments on Tempo
@app.get("/paid")
async def get_api(request: Request):
recipient_address = await create_pay_to_address(request)
mpp = Mpp.create(
method=tempo(
currency=PATH_USD,
recipient=recipient_address,
intents={"charge": ChargeIntent()},
chain_id=42431,
),
secret_key=mpp_secret_key,
)
result = await mpp.charge(
authorization=request.headers.get("authorization"),
amount="0.01",
)
if isinstance(result, Challenge):
return JSONResponse(
status_code=402,
content={"error": "Payment required"},
headers={"WWW-Authenticate": result.to_www_authenticate(mpp.realm)},
)
_credential, receipt = result
response = JSONResponse(content={"foo": "bar"})
response.headers["Authentication-Info"] = receipt.to_payment_receipt()
return response
if __name__ == "__main__":
print("Server listening at http://localhost:4242")
uvicorn.run(app, host="0.0.0.0", port=4242)
// Stripe handles payment processing for both crypto and SPT methods
if (!process.env.STRIPE_SECRET_KEY) {
console.error("STRIPE_SECRET_KEY environment variable is required");
process.exit(1);
}
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
apiVersion: "2026-03-04.preview" as any,
appInfo: {
name: "stripe-samples/machine-payments",
url: "https://github.com/stripe-samples/machine-payments",
version: "1.0.0",
},
});
// Secret used to secure payment challenges
// https://mpp.dev/protocol/challenges#challenge-binding
const mppSecretKey = crypto.randomBytes(32).toString('base64');
// In-memory cache for deposit addresses (TTL: 5 minutes)
// NOTE: For production, use a distributed cache like Redis instead of node-cache
const paymentCache = new NodeCache({ stdTTL: 300, checkperiod: 60 });
// This function determines where crypto payments should be sent. It either:
// 1. Extracts the address from an existing payment header (for retry/verification), or
// 2. Creates a new Stripe PaymentIntent to generate a fresh deposit address.
async function createPayToAddress(request: Request): Promise {
const authHeader = request.headers.get('authorization')
if (authHeader && Credential.extractPaymentScheme(authHeader)) {
const credential = Credential.fromRequest(request)
const toAddress = credential.challenge.request.recipient as `0x${string}`
if (!paymentCache.has(toAddress)) {
throw new Error('Invalid payTo address: not found in server cache')
}
return toAddress
}
// Create a new PaymentIntent to get a fresh crypto deposit address
const decimals = 6; // USDC has 6 decimals
const amountInCents = Number(1000000) / Math.pow(10, decimals - 2);
const paymentIntent = await stripe.paymentIntents.create({
amount: amountInCents,
currency: "usd",
payment_method_types: ["crypto"],
payment_method_data: {
type: "crypto",
},
payment_method_options: {
crypto: {
mode: "deposit",
deposit_options: { networks: ["tempo"] },
} as any,
},
confirm: true,
});
if (
!paymentIntent.next_action ||
!("crypto_display_details" in paymentIntent.next_action)
) {
throw new Error(
"PaymentIntent did not return expected crypto deposit details",
);
}
// Extract the Tempo network deposit address from the PaymentIntent
const depositDetails = paymentIntent.next_action
.crypto_display_details as any;
const payToAddress = depositDetails.deposit_addresses["tempo"]
.address as string;
console.log(
`Created PaymentIntent ${paymentIntent.id} for $${(
amountInCents / 100
).toFixed(2)} -> ${payToAddress}`,
);
paymentCache.set(payToAddress, true);
return payToAddress;
}
// Create Mppx instance for SPT payments (cards and Link)
const mppxSpt = Mppx.create({
methods: [
mppxStripe.charge({
networkId: 'internal',
paymentMethodTypes: ['card', 'link'],
secretKey: process.env.STRIPE_SECRET_KEY,
}),
],
secretKey: mppSecretKey
});
const PATH_USD = '0x20c0000000000000000000000000000000000000';
const app = new Hono()
// GET /crypto/paid - Accept crypto payments on Tempo
app.get('/crypto/paid', async (c) => {
const request = c.req.raw
const recipientAddress = await createPayToAddress(request)
const mppxCrypto = Mppx.create({
methods: [
tempo.charge({
currency: PATH_USD,
recipient: recipientAddress,
testnet: true,
}),
],
secretKey: mppSecretKey,
})
const response = await mppxCrypto.charge({ amount: '1' })(request)
if (response.status === 402) {
return response.challenge
}
return response.withReceipt(
Response.json({
data: 'Premium content delivered via crypto!',
timestamp: new Date().toISOString(),
})
)
})
// GET /spt/paid - Accept SPT payments (cards and Link)
app.get('/spt/paid', async (c) => {
const request = c.req.raw
const result = await mppxSpt.charge({
amount: '1',
currency: 'usd',
})(request);
if (result.status === 402) {
return result.challenge
}
return result.withReceipt(
Response.json({
data: 'Premium content delivered via SPT!',
timestamp: new Date().toISOString(),
})
)
})
serve({
fetch: app.fetch,
port: 4242,
});
console.log(`Server listening at http://localhost:4242`);
console.log(`Crypto endpoint: http://localhost:4242/crypto/paid`);
console.log(`SPT endpoint: http://localhost:4242/spt/paid`);
## Nächste Schritte
- [Maschinelle Zahlungen](https://docs.stripe.com/payments/machine.md)
- [MPP](https://docs.stripe.com/payments/machine/mpp.md)