# 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)