# Démarrage rapide du MPP
Créez un serveur qui accepte les paiements automatisés en cryptomonnaie ou en monnaie fiduciaire.
## Générateur d’endpoints de paiement MPP
Apprenez comment créer et déployer un serveur capable d’accepter à la fois les paiements en cryptomonnaie et ceux en token de paiement partagé (SPT), et ce, à l’aide du Protocole de paiement machine (MPP).
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
### Initialiser Stripe
Configurez le client Stripe avec votre clé secrète, et définissez la version API sur `2026-03-04.preview`. Le client traite le paiement des cryptomonnaie et SPT.
Assurez-vous d’avoir [activé les cryptomonnaies](https://support.stripe.com/questions/get-started-with-pay-with-crypto) pour votre compte Stripe.
### Créer le gestionnaire de PaymentIntent
Créez une fonction qui détermine où envoyer les paiements par cryptomonnaie. Extrayez l’adresse d’un en-tête de paiement existant pour les nouvelles tentatives ou la vérification, ou [créez un nouveau PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md) afin de générer une nouvelle adresse de dépôt.
Lorsque vous créez un [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) avec le *moyen de paiement* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) `crypto` et le mode `deposit`, indiquez les réseaux que vous souhaitez prendre en charge à l’aide de `deposit_options`. Stripe renvoie des adresses de dépôt pour les réseaux demandés. La fonction extrait l’adresse du réseau Tempo que les clients utilisent pour envoyer des *stablecoins* (A cryptocurrency that's pegged to the value of a fiat currency or other asset in order to limit volatility).
### Créer un gestionnaire de paiement par SPT côté serveur
Configurez un gestionnaire de paiement côté serveur pour les SPT à l’aide de [Mppx.create](https://mpp.dev/sdk/typescript/server/Mppx.create). Configurez-le de manière à accepter les paiements par cartes et par Link en utilisant le traitement des paiements de Stripe.
### Créer l’application Hono
Initialisez le serveur Hono qui héberge les deux endpoints de paiement.
### Créer l’application FastAPI
Initialisez le serveur FastAPI qui héberge l’endpoint de paiement.
### Créer un assistant de test pour SPT
Ajoutez un endpoint `POST` pour créer des SPT à des fins de test.
En mode production, le back-end du client appelant émettrait des SPT, et non votre endpoint protégé.
### Créer un endpoint de paiement en cryptomonnaies
Définissez l’endpoint `/crypto/paid` qui accepte les paiements par cryptomonnaie.
- Créez un gestionnaire de paiement côté serveur pour Tempo en utilisant [Mppx.create](https://mpp.dev/sdk/typescript/server/Mppx.create).
- Renvoie une réponse `402 Paiement requis` avec les détails de paiement lorsque la requête ne contient pas de paiement valide.
- Vérifie les difficultés de paiement pour chaque requête.
- Autoriser l’accès lorsque la requête inclut un identifiant de paiement valide.
### Créer un endpoint de paiement en cryptomonnaies
Définissez l’endpoint `/paid` qui accepte les paiements par cryptomonnaie sur Tempo.
- Créez un gestionnaire de paiement côté serveur pour Tempo avec [Mpp.create](https://mpp.dev/sdk/python/server/Mpp.create).
- Cherchez un identifiant de paiement valide pour chaque requête.
- Si la requête n’inclut pas d’identifiant de paiement valide, renvoyez une réponse `402 Payment Required` avec les informations de paiement du gestionnaire Tempo.
- Si la requête inclut un défi de paiement, vérifiez-le avec du gestionnaire Tempo.
- N’autorisez l’accès qu’une fois que l’identifiant ou le défi de paiement est valide.
### Créer un endpoint de paiement par SPT
Définissez l’endpoint `/spt/paid` qui accepte les paiements par SPT.
- Renvoie une réponse `402 Paiement requis` avec les détails de paiement lorsque la requête ne contient pas de paiement valide.
- Vérifie les difficultés de paiement pour chaque requête.
- Autoriser l’accès lorsque la requête inclut un identifiant de paiement valide.
### Configurer la méthode de paiement
Configurez la méthode de paiement côté client pour créer des SPT. La fonction `createToken` appelle l’endpoint `/create-spt` de votre back-end pour générer des tokens de paiement partagés.
### Obtenir le défi du paiement
Récupérez le défi `402` à partir de l’endpoint protégé pour comprendre les exigences de paiement.
### Fournir un moyen de paiement
Spécifiez le moyen de paiement à utiliser. Dans cet exemple, le code utilise un moyen de paiement test par carte bancaire.
### Créer un identifiant de paiement
Utilisez la méthode de paiement pour créer un identifiant de paiement à partir du défi et du moyen de paiement.
### Réessayer avec un identifiant
Effectuez une autre requête à l’endpoint protégé avec l’identifiant de paiement dans l’en-tête `Authorization`.
### Exécuter le serveur
Développez et exécutez votre serveur pour tester les deux endpoints.
```bash
npm run dev
```
### Exécuter le serveur
Développer et exécuter votre serveur pour tester l’endpoint à `http://localhost:4242/paid`.
```bash
uv run python main.py
```
### Essai sans paiement
Effectuez une requête auprès de l’endpoint de cryptomonnaie sans paiement pour confirmer qu’il renvoie un code d’état `402` avec les détails de paiement.
```bash
curl http://localhost:4242/crypto/paid
```
Vous recevrez une réponse `402 Payment Required` contenant les informations de paiement MPP (Machine Payment Protocol).
### Essai sans paiement
Effectuez une requête auprès de l’endpoint sans paiement pour confirmer qu’il renvoie un code d’état `402` avec les détails de paiement.
```bash
curl http://localhost:4242/paid
```
Vous recevrez une réponse `402 Payment Required` contenant les informations de paiement MPP (Machine Payment Protocol).
### Test de paiements en cryptomonnaie
Utilisez l’outil [mppx](https://www.npmjs.com/package/mppx) de Tempo pour tester le tunnel de paiement en cryptomonnaies. L’outil gère le MPP et effectue le paiement automatiquement.
```bash
mppx http://localhost:4242/crypto/paid
```
Vous pouvez créer et financer un wallet test avec `mppx account create` et `mppx account fund`. Le serveur renvoie le contenu après un paiement réussi. Vous pouvez confirmer le paiement dans le [Dashboard de Stripe](https://dashboard.stripe.com) sous **Paiements**.
### Test de paiements en cryptomonnaie
Utilisez l’outil [mppx](https://www.npmjs.com/package/mppx) de Tempo pour tester le tunnel de paiement en cryptomonnaies. L’outil gère le MPP et effectue le paiement automatiquement.
```bash
mppx http://localhost:4242/paid
```
Vous pouvez créer et financer un wallet test avec `mppx account create` et `mppx account fund`. Après un paiement réussi, le serveur renvoie le contenu. Vous pouvez confirmer le paiement dans le [Dashboard Stripe](https://dashboard.stripe.com) sous **Paiements**.
### Tester les paiements SPT
Pour les paiements SPT, utilisez le script `client.ts` inclus qui illustre le tunnel de paiement complet avec les SPT.
```bash
npx tsx client.ts
```
Le script client :
1. Récupère le défi `402` de `/spt/paid`
1. Crée un SPT à l’aide de l’endpoint assistant `/create-spt`
1. Crée un identifiant de paiement
1. Récupère la requête avec l’identifiant pour accéder à la ressource protégée
Vous pouvez confirmer le paiement dans le [Dashboard de Stripe](https://dashboard.stripe.com) sous **Paiements**.
- 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`);
## Étapes suivantes
- [Paiements automatiques](https://docs.stripe.com/payments/machine.md)
- [MPP](https://docs.stripe.com/payments/machine/mpp.md)